[{"data":1,"prerenderedAt":1496},["ShallowReactive",2],{"nav":3,"page-\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fglobal-exception-handlers-for-consistent-api-responses\u002F":152,"surround-\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fglobal-exception-handlers-for-consistent-api-responses\u002F":1494},[4,72],{"title":5,"path":6,"stem":7,"children":8},"Advanced Pydantic Validation Serialization","\u002Fadvanced-pydantic-validation-serialization","advanced-pydantic-validation-serialization",[9,12,24,36,48,54,66],{"title":10,"path":6,"stem":11},"Advanced Pydantic Validation & Serialization","advanced-pydantic-validation-serialization\u002Findex",{"title":13,"path":14,"stem":15,"children":16},"Custom Validators & Field Constraints in FastAPI & Pydantic V2","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Findex",[17,18],{"title":13,"path":14,"stem":15},{"title":19,"path":20,"stem":21,"children":22},"Creating Reusable Custom Validators in Pydantic: Production Patterns","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fcreating-reusable-custom-validators-in-pydantic","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fcreating-reusable-custom-validators-in-pydantic\u002Findex",[23],{"title":19,"path":20,"stem":21},{"title":25,"path":26,"stem":27,"children":28},"JSON Schema Customization","\u002Fadvanced-pydantic-validation-serialization\u002Fjson-schema-customization","advanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Findex",[29,30],{"title":25,"path":26,"stem":27},{"title":31,"path":32,"stem":33,"children":34},"Customizing OpenAPI Schema Generation in FastAPI: Production Implementation Guide","\u002Fadvanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fcustomizing-openapi-schema-generation-in-fastapi","advanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fcustomizing-openapi-schema-generation-in-fastapi\u002Findex",[35],{"title":31,"path":32,"stem":33},{"title":37,"path":38,"stem":39,"children":40},"Mastering Nested Model Serialization in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization","advanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Findex",[41,42],{"title":37,"path":38,"stem":39},{"title":43,"path":44,"stem":45,"children":46},"Handling Deeply Nested JSON Models Efficiently in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fhandling-deeply-nested-json-models-efficiently","advanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fhandling-deeply-nested-json-models-efficiently\u002Findex",[47],{"title":43,"path":44,"stem":45},{"title":49,"path":50,"stem":51,"children":52},"Performance Optimization for Models in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models","advanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Findex",[53],{"title":49,"path":50,"stem":51},{"title":55,"path":56,"stem":57,"children":58},"Pydantic V2 Migration Guide: FastAPI Production Patterns","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Findex",[59,60],{"title":55,"path":56,"stem":57},{"title":61,"path":62,"stem":63,"children":64},"Migrating from Pydantic v1 to v2 without breaking APIs","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrating-from-pydantic-v1-to-v2-without-breaking-apis","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrating-from-pydantic-v1-to-v2-without-breaking-apis\u002Findex",[65],{"title":61,"path":62,"stem":63},{"title":67,"path":68,"stem":69,"children":70},"Type Hinting & IDE Integration in FastAPI: Advanced Pydantic Patterns","\u002Fadvanced-pydantic-validation-serialization\u002Ftype-hinting-ide-integration","advanced-pydantic-validation-serialization\u002Ftype-hinting-ide-integration\u002Findex",[71],{"title":67,"path":68,"stem":69},{"title":73,"path":74,"stem":75,"children":76},"Core Architecture Routing Patterns","\u002Fcore-architecture-routing-patterns","core-architecture-routing-patterns",[77,80,92,104,116,128,140],{"title":78,"path":74,"stem":79},"Core Architecture & Routing Patterns in FastAPI: A Production-Ready Blueprint","core-architecture-routing-patterns\u002Findex",{"title":81,"path":82,"stem":83,"children":84},"Application Factory Patterns in FastAPI: Production Architecture Guide","\u002Fcore-architecture-routing-patterns\u002Fapplication-factory-patterns","core-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Findex",[85,86],{"title":81,"path":82,"stem":83},{"title":87,"path":88,"stem":89,"children":90},"FastAPI App Factory Pattern for Testing and Deployment: Production Guide","\u002Fcore-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Ffastapi-app-factory-pattern-for-testing-and-deployment","core-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Ffastapi-app-factory-pattern-for-testing-and-deployment\u002Findex",[91],{"title":87,"path":88,"stem":89},{"title":93,"path":94,"stem":95,"children":96},"Configuration Management in FastAPI: Production-Ready Patterns & Security","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management","core-architecture-routing-patterns\u002Fconfiguration-management\u002Findex",[97,98],{"title":93,"path":94,"stem":95},{"title":99,"path":100,"stem":101,"children":102},"Managing Environment Variables with Pydantic Settings in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fmanaging-environment-variables-with-pydantic-settings","core-architecture-routing-patterns\u002Fconfiguration-management\u002Fmanaging-environment-variables-with-pydantic-settings\u002Findex",[103],{"title":99,"path":100,"stem":101},{"title":105,"path":106,"stem":107,"children":108},"Dependency Injection Strategies","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Findex",[109,110],{"title":105,"path":106,"stem":107},{"title":111,"path":112,"stem":113,"children":114},"Best Practices for FastAPI Dependency Injection","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fbest-practices-for-fastapi-dependency-injection","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fbest-practices-for-fastapi-dependency-injection\u002Findex",[115],{"title":111,"path":112,"stem":113},{"title":117,"path":118,"stem":119,"children":120},"Error Handling & Global Exceptions in FastAPI","\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions","core-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Findex",[121,122],{"title":117,"path":118,"stem":119},{"title":123,"path":124,"stem":125,"children":126},"Global Exception Handlers for Consistent API Responses","\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fglobal-exception-handlers-for-consistent-api-responses","core-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fglobal-exception-handlers-for-consistent-api-responses\u002Findex",[127],{"title":123,"path":124,"stem":125},{"title":129,"path":130,"stem":131,"children":132},"Middleware Implementation","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Findex",[133,134],{"title":129,"path":130,"stem":131},{"title":135,"path":136,"stem":137,"children":138},"Implementing Custom Middleware for Request Tracing in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fimplementing-custom-middleware-for-request-tracing","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fimplementing-custom-middleware-for-request-tracing\u002Findex",[139],{"title":135,"path":136,"stem":137},{"title":141,"path":142,"stem":143,"children":144},"Modular Router Organization in FastAPI: Production-Grade Architecture","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Findex",[145,146],{"title":141,"path":142,"stem":143},{"title":147,"path":148,"stem":149,"children":150},"How to Structure Large FastAPI Projects for Scale","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization\u002Fhow-to-structure-large-fastapi-projects-for-scale","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Fhow-to-structure-large-fastapi-projects-for-scale\u002Findex",[151],{"title":147,"path":148,"stem":149},{"id":153,"title":123,"body":154,"description":1489,"extension":1490,"meta":1491,"navigation":277,"path":124,"seo":1492,"stem":125,"__hash__":1493},"content\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fglobal-exception-handlers-for-consistent-api-responses\u002Findex.md",{"type":155,"value":156,"toc":1481},"minimark",[157,161,176,181,189,542,546,560,762,766,777,1112,1116,1131,1356,1360,1437,1441,1447,1450,1455,1469,1474,1477],[158,159,123],"h1",{"id":160},"global-exception-handlers-for-consistent-api-responses",[162,163,164,165,169,170,175],"p",{},"Implementing global exception handlers for consistent API responses eliminates fragmented ",[166,167,168],"code",{},"try\u002Fexcept"," blocks and guarantees predictable client payloads across microservices. This guide covers immediate implementation, environment-aware debugging, and centralized configuration within modern ",[171,172,174],"a",{"href":173},"\u002Fcore-architecture-routing-patterns\u002F","Core Architecture & Routing Patterns",". By centralizing error routing, you enforce strict JSON schemas via Pydantic models and toggle verbose stack traces based on deployment environment.",[177,178,180],"h2",{"id":179},"registering-base-exception-handlers","Registering Base Exception Handlers",[162,182,183,184,188],{},"Map FastAPI’s exception router to catch unhandled Python errors and HTTP status codes uniformly. You must safely override Starlette defaults and strictly prioritize registration order—FastAPI applies a last-registered-wins strategy for duplicate exception types. Always capture request context early to preserve headers, paths, and correlation IDs for downstream observability. For deeper mechanics on exception routing and Starlette integration, consult ",[171,185,187],{"href":186},"\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002F","Error Handling & Global Exceptions",".",[190,191,196],"pre",{"className":192,"code":193,"language":194,"meta":195,"style":195},"language-python shiki shiki-themes github-light","from fastapi import FastAPI, Request, HTTPException\nfrom fastapi.responses import JSONResponse\nfrom pydantic import BaseModel\nfrom typing import Optional\nimport uuid\nimport logging\n\napp = FastAPI()\nlogger = logging.getLogger(\"api.exceptions\")\n\nclass ErrorResponse(BaseModel):\n code: str\n detail: str\n trace_id: Optional[str] = None\n\n@app.exception_handler(Exception)\nasync def global_exception_handler(request: Request, exc: Exception) -> JSONResponse:\n # Preserve distributed tracing context\n trace_id = request.headers.get(\"X-Correlation-ID\", str(uuid.uuid4()))\n \n # Production-safe detail masking\n detail = str(exc) if app.debug else \"An unexpected server error occurred.\"\n \n error = ErrorResponse(code=\"INTERNAL_ERROR\", detail=detail, trace_id=trace_id)\n return JSONResponse(status_code=500, content=error.model_dump())\n","python","",[166,197,198,217,230,243,256,264,272,279,291,309,314,333,343,351,368,373,386,406,413,435,441,447,473,478,515],{"__ignoreMap":195},[199,200,203,207,211,214],"span",{"class":201,"line":202},"line",1,[199,204,206],{"class":205},"sD7c4","from",[199,208,210],{"class":209},"sgsFI"," fastapi ",[199,212,213],{"class":205},"import",[199,215,216],{"class":209}," FastAPI, Request, HTTPException\n",[199,218,220,222,225,227],{"class":201,"line":219},2,[199,221,206],{"class":205},[199,223,224],{"class":209}," fastapi.responses ",[199,226,213],{"class":205},[199,228,229],{"class":209}," JSONResponse\n",[199,231,233,235,238,240],{"class":201,"line":232},3,[199,234,206],{"class":205},[199,236,237],{"class":209}," pydantic ",[199,239,213],{"class":205},[199,241,242],{"class":209}," BaseModel\n",[199,244,246,248,251,253],{"class":201,"line":245},4,[199,247,206],{"class":205},[199,249,250],{"class":209}," typing ",[199,252,213],{"class":205},[199,254,255],{"class":209}," Optional\n",[199,257,259,261],{"class":201,"line":258},5,[199,260,213],{"class":205},[199,262,263],{"class":209}," uuid\n",[199,265,267,269],{"class":201,"line":266},6,[199,268,213],{"class":205},[199,270,271],{"class":209}," logging\n",[199,273,275],{"class":201,"line":274},7,[199,276,278],{"emptyLinePlaceholder":277},true,"\n",[199,280,282,285,288],{"class":201,"line":281},8,[199,283,284],{"class":209},"app ",[199,286,287],{"class":205},"=",[199,289,290],{"class":209}," FastAPI()\n",[199,292,294,297,299,302,306],{"class":201,"line":293},9,[199,295,296],{"class":209},"logger ",[199,298,287],{"class":205},[199,300,301],{"class":209}," logging.getLogger(",[199,303,305],{"class":304},"sYBdl","\"api.exceptions\"",[199,307,308],{"class":209},")\n",[199,310,312],{"class":201,"line":311},10,[199,313,278],{"emptyLinePlaceholder":277},[199,315,317,320,324,327,330],{"class":201,"line":316},11,[199,318,319],{"class":205},"class",[199,321,323],{"class":322},"s7eDp"," ErrorResponse",[199,325,326],{"class":209},"(",[199,328,329],{"class":322},"BaseModel",[199,331,332],{"class":209},"):\n",[199,334,336,339],{"class":201,"line":335},12,[199,337,338],{"class":209}," code: ",[199,340,342],{"class":341},"sYu0t","str\n",[199,344,346,349],{"class":201,"line":345},13,[199,347,348],{"class":209}," detail: ",[199,350,342],{"class":341},[199,352,354,357,360,363,365],{"class":201,"line":353},14,[199,355,356],{"class":209}," trace_id: Optional[",[199,358,359],{"class":341},"str",[199,361,362],{"class":209},"] ",[199,364,287],{"class":205},[199,366,367],{"class":341}," None\n",[199,369,371],{"class":201,"line":370},15,[199,372,278],{"emptyLinePlaceholder":277},[199,374,376,379,381,384],{"class":201,"line":375},16,[199,377,378],{"class":322},"@app.exception_handler",[199,380,326],{"class":209},[199,382,383],{"class":341},"Exception",[199,385,308],{"class":209},[199,387,389,392,395,398,401,403],{"class":201,"line":388},17,[199,390,391],{"class":205},"async",[199,393,394],{"class":205}," def",[199,396,397],{"class":322}," global_exception_handler",[199,399,400],{"class":209},"(request: Request, exc: ",[199,402,383],{"class":341},[199,404,405],{"class":209},") -> JSONResponse:\n",[199,407,409],{"class":201,"line":408},18,[199,410,412],{"class":411},"sAwPA"," # Preserve distributed tracing context\n",[199,414,416,419,421,424,427,430,432],{"class":201,"line":415},19,[199,417,418],{"class":209}," trace_id ",[199,420,287],{"class":205},[199,422,423],{"class":209}," request.headers.get(",[199,425,426],{"class":304},"\"X-Correlation-ID\"",[199,428,429],{"class":209},", ",[199,431,359],{"class":341},[199,433,434],{"class":209},"(uuid.uuid4()))\n",[199,436,438],{"class":201,"line":437},20,[199,439,440],{"class":209}," \n",[199,442,444],{"class":201,"line":443},21,[199,445,446],{"class":411}," # Production-safe detail masking\n",[199,448,450,453,455,458,461,464,467,470],{"class":201,"line":449},22,[199,451,452],{"class":209}," detail ",[199,454,287],{"class":205},[199,456,457],{"class":341}," str",[199,459,460],{"class":209},"(exc) ",[199,462,463],{"class":205},"if",[199,465,466],{"class":209}," app.debug ",[199,468,469],{"class":205},"else",[199,471,472],{"class":304}," \"An unexpected server error occurred.\"\n",[199,474,476],{"class":201,"line":475},23,[199,477,440],{"class":209},[199,479,481,484,486,489,492,494,497,499,502,504,507,510,512],{"class":201,"line":480},24,[199,482,483],{"class":209}," error ",[199,485,287],{"class":205},[199,487,488],{"class":209}," ErrorResponse(",[199,490,166],{"class":491},"sqxcx",[199,493,287],{"class":205},[199,495,496],{"class":304},"\"INTERNAL_ERROR\"",[199,498,429],{"class":209},[199,500,501],{"class":491},"detail",[199,503,287],{"class":205},[199,505,506],{"class":209},"detail, ",[199,508,509],{"class":491},"trace_id",[199,511,287],{"class":205},[199,513,514],{"class":209},"trace_id)\n",[199,516,518,521,524,527,529,532,534,537,539],{"class":201,"line":517},25,[199,519,520],{"class":205}," return",[199,522,523],{"class":209}," JSONResponse(",[199,525,526],{"class":491},"status_code",[199,528,287],{"class":205},[199,530,531],{"class":341},"500",[199,533,429],{"class":209},[199,535,536],{"class":491},"content",[199,538,287],{"class":205},[199,540,541],{"class":209},"error.model_dump())\n",[177,543,545],{"id":544},"structuring-unified-error-responses","Structuring Unified Error Responses",[162,547,548,549,429,551,553,554,556,557,559],{},"Define reusable Pydantic models to standardize ",[166,550,501],{},[166,552,166],{},", and ",[166,555,509],{}," fields across all failure states. Inherit from ",[166,558,329],{}," for strict validation, map HTTP status codes to internal error enums, and inject correlation IDs for distributed tracing. This prevents client-side parsing failures when downstream services return heterogeneous error formats.",[190,561,563],{"className":192,"code":562,"language":194,"meta":195,"style":195},"from enum import Enum\nfrom fastapi.exceptions import RequestValidationError\n\nclass ErrorCode(str, Enum):\n VALIDATION_FAILED = \"VALIDATION_FAILED\"\n AUTHENTICATION_REQUIRED = \"AUTHENTICATION_REQUIRED\"\n INTERNAL_ERROR = \"INTERNAL_ERROR\"\n\n@app.exception_handler(RequestValidationError)\nasync def validation_exception_handler(request: Request, exc: RequestValidationError) -> JSONResponse:\n trace_id = request.headers.get(\"X-Correlation-ID\", str(uuid.uuid4()))\n \n return JSONResponse(\n status_code=422,\n content=ErrorResponse(\n code=ErrorCode.VALIDATION_FAILED,\n detail=\"Invalid request payload.\",\n trace_id=trace_id\n ).model_dump()\n )\n",[166,564,565,577,589,593,611,622,632,642,646,653,665,681,685,692,705,715,730,742,752,757],{"__ignoreMap":195},[199,566,567,569,572,574],{"class":201,"line":202},[199,568,206],{"class":205},[199,570,571],{"class":209}," enum ",[199,573,213],{"class":205},[199,575,576],{"class":209}," Enum\n",[199,578,579,581,584,586],{"class":201,"line":219},[199,580,206],{"class":205},[199,582,583],{"class":209}," fastapi.exceptions ",[199,585,213],{"class":205},[199,587,588],{"class":209}," RequestValidationError\n",[199,590,591],{"class":201,"line":232},[199,592,278],{"emptyLinePlaceholder":277},[199,594,595,597,600,602,604,606,609],{"class":201,"line":245},[199,596,319],{"class":205},[199,598,599],{"class":322}," ErrorCode",[199,601,326],{"class":209},[199,603,359],{"class":341},[199,605,429],{"class":209},[199,607,608],{"class":322},"Enum",[199,610,332],{"class":209},[199,612,613,616,619],{"class":201,"line":258},[199,614,615],{"class":341}," VALIDATION_FAILED",[199,617,618],{"class":205}," =",[199,620,621],{"class":304}," \"VALIDATION_FAILED\"\n",[199,623,624,627,629],{"class":201,"line":266},[199,625,626],{"class":341}," AUTHENTICATION_REQUIRED",[199,628,618],{"class":205},[199,630,631],{"class":304}," \"AUTHENTICATION_REQUIRED\"\n",[199,633,634,637,639],{"class":201,"line":274},[199,635,636],{"class":341}," INTERNAL_ERROR",[199,638,618],{"class":205},[199,640,641],{"class":304}," \"INTERNAL_ERROR\"\n",[199,643,644],{"class":201,"line":281},[199,645,278],{"emptyLinePlaceholder":277},[199,647,648,650],{"class":201,"line":293},[199,649,378],{"class":322},[199,651,652],{"class":209},"(RequestValidationError)\n",[199,654,655,657,659,662],{"class":201,"line":311},[199,656,391],{"class":205},[199,658,394],{"class":205},[199,660,661],{"class":322}," validation_exception_handler",[199,663,664],{"class":209},"(request: Request, exc: RequestValidationError) -> JSONResponse:\n",[199,666,667,669,671,673,675,677,679],{"class":201,"line":316},[199,668,418],{"class":209},[199,670,287],{"class":205},[199,672,423],{"class":209},[199,674,426],{"class":304},[199,676,429],{"class":209},[199,678,359],{"class":341},[199,680,434],{"class":209},[199,682,683],{"class":201,"line":335},[199,684,440],{"class":209},[199,686,687,689],{"class":201,"line":345},[199,688,520],{"class":205},[199,690,691],{"class":209}," JSONResponse(\n",[199,693,694,697,699,702],{"class":201,"line":353},[199,695,696],{"class":491}," status_code",[199,698,287],{"class":205},[199,700,701],{"class":341},"422",[199,703,704],{"class":209},",\n",[199,706,707,710,712],{"class":201,"line":370},[199,708,709],{"class":491}," content",[199,711,287],{"class":205},[199,713,714],{"class":209},"ErrorResponse(\n",[199,716,717,720,722,725,728],{"class":201,"line":375},[199,718,719],{"class":491}," code",[199,721,287],{"class":205},[199,723,724],{"class":209},"ErrorCode.",[199,726,727],{"class":341},"VALIDATION_FAILED",[199,729,704],{"class":209},[199,731,732,735,737,740],{"class":201,"line":388},[199,733,734],{"class":491}," detail",[199,736,287],{"class":205},[199,738,739],{"class":304},"\"Invalid request payload.\"",[199,741,704],{"class":209},[199,743,744,747,749],{"class":201,"line":408},[199,745,746],{"class":491}," trace_id",[199,748,287],{"class":205},[199,750,751],{"class":209},"trace_id\n",[199,753,754],{"class":201,"line":415},[199,755,756],{"class":209}," ).model_dump()\n",[199,758,759],{"class":201,"line":437},[199,760,761],{"class":209}," )\n",[177,763,765],{"id":764},"debugging-production-exceptions","Debugging Production Exceptions",[162,767,768,769,772,773,776],{},"Implement conditional logging and safe stack trace exposure without leaking sensitive internals. Differentiate between ",[166,770,771],{},"4xx"," and ",[166,774,775],{},"5xx"," error verbosity, integrate structured JSON logging, and suppress framework-level noise during high traffic. Raw tracebacks should never reach the HTTP response layer; they belong exclusively in centralized log aggregators.",[190,778,780],{"className":192,"code":779,"language":194,"meta":195,"style":195},"import traceback\nfrom pydantic_settings import BaseSettings, SettingsConfigDict\n\nclass Settings(BaseSettings):\n model_config = SettingsConfigDict(env_file=\".env\")\n APP_ENV: str = \"production\"\n SHOW_TRACEBACKS: bool = False\n\nsettings = Settings()\n\n@app.exception_handler(Exception)\nasync def production_exception_handler(request: Request, exc: Exception) -> JSONResponse:\n trace_id = request.headers.get(\"X-Correlation-ID\", str(uuid.uuid4()))\n \n # Structured logging for observability platforms (Datadog, ELK, CloudWatch)\n logger.error(\n \"Unhandled exception\",\n extra={\n \"trace_id\": trace_id,\n \"path\": request.url.path,\n \"method\": request.method,\n \"exception_type\": type(exc).__name__,\n \"traceback\": traceback.format_exc() if settings.SHOW_TRACEBACKS else None\n }\n )\n\n detail = str(exc) if settings.SHOW_TRACEBACKS else \"Internal server error\"\n return JSONResponse(\n status_code=500,\n content=ErrorResponse(code=\"INTERNAL_ERROR\", detail=detail, trace_id=trace_id).model_dump()\n )\n",[166,781,782,789,801,805,819,839,854,869,873,883,887,897,912,928,932,937,942,949,959,967,975,983,1001,1022,1027,1031,1036,1058,1065,1076,1107],{"__ignoreMap":195},[199,783,784,786],{"class":201,"line":202},[199,785,213],{"class":205},[199,787,788],{"class":209}," traceback\n",[199,790,791,793,796,798],{"class":201,"line":219},[199,792,206],{"class":205},[199,794,795],{"class":209}," pydantic_settings ",[199,797,213],{"class":205},[199,799,800],{"class":209}," BaseSettings, SettingsConfigDict\n",[199,802,803],{"class":201,"line":232},[199,804,278],{"emptyLinePlaceholder":277},[199,806,807,809,812,814,817],{"class":201,"line":245},[199,808,319],{"class":205},[199,810,811],{"class":322}," Settings",[199,813,326],{"class":209},[199,815,816],{"class":322},"BaseSettings",[199,818,332],{"class":209},[199,820,821,824,826,829,832,834,837],{"class":201,"line":258},[199,822,823],{"class":209}," model_config ",[199,825,287],{"class":205},[199,827,828],{"class":209}," SettingsConfigDict(",[199,830,831],{"class":491},"env_file",[199,833,287],{"class":205},[199,835,836],{"class":304},"\".env\"",[199,838,308],{"class":209},[199,840,841,844,847,849,851],{"class":201,"line":266},[199,842,843],{"class":341}," APP_ENV",[199,845,846],{"class":209},": ",[199,848,359],{"class":341},[199,850,618],{"class":205},[199,852,853],{"class":304}," \"production\"\n",[199,855,856,859,861,864,866],{"class":201,"line":274},[199,857,858],{"class":341}," SHOW_TRACEBACKS",[199,860,846],{"class":209},[199,862,863],{"class":341},"bool",[199,865,618],{"class":205},[199,867,868],{"class":341}," False\n",[199,870,871],{"class":201,"line":281},[199,872,278],{"emptyLinePlaceholder":277},[199,874,875,878,880],{"class":201,"line":293},[199,876,877],{"class":209},"settings ",[199,879,287],{"class":205},[199,881,882],{"class":209}," Settings()\n",[199,884,885],{"class":201,"line":311},[199,886,278],{"emptyLinePlaceholder":277},[199,888,889,891,893,895],{"class":201,"line":316},[199,890,378],{"class":322},[199,892,326],{"class":209},[199,894,383],{"class":341},[199,896,308],{"class":209},[199,898,899,901,903,906,908,910],{"class":201,"line":335},[199,900,391],{"class":205},[199,902,394],{"class":205},[199,904,905],{"class":322}," production_exception_handler",[199,907,400],{"class":209},[199,909,383],{"class":341},[199,911,405],{"class":209},[199,913,914,916,918,920,922,924,926],{"class":201,"line":345},[199,915,418],{"class":209},[199,917,287],{"class":205},[199,919,423],{"class":209},[199,921,426],{"class":304},[199,923,429],{"class":209},[199,925,359],{"class":341},[199,927,434],{"class":209},[199,929,930],{"class":201,"line":353},[199,931,440],{"class":209},[199,933,934],{"class":201,"line":370},[199,935,936],{"class":411}," # Structured logging for observability platforms (Datadog, ELK, CloudWatch)\n",[199,938,939],{"class":201,"line":375},[199,940,941],{"class":209}," logger.error(\n",[199,943,944,947],{"class":201,"line":388},[199,945,946],{"class":304}," \"Unhandled exception\"",[199,948,704],{"class":209},[199,950,951,954,956],{"class":201,"line":408},[199,952,953],{"class":491}," extra",[199,955,287],{"class":205},[199,957,958],{"class":209},"{\n",[199,960,961,964],{"class":201,"line":415},[199,962,963],{"class":304}," \"trace_id\"",[199,965,966],{"class":209},": trace_id,\n",[199,968,969,972],{"class":201,"line":437},[199,970,971],{"class":304}," \"path\"",[199,973,974],{"class":209},": request.url.path,\n",[199,976,977,980],{"class":201,"line":443},[199,978,979],{"class":304}," \"method\"",[199,981,982],{"class":209},": request.method,\n",[199,984,985,988,990,993,996,999],{"class":201,"line":449},[199,986,987],{"class":304}," \"exception_type\"",[199,989,846],{"class":209},[199,991,992],{"class":341},"type",[199,994,995],{"class":209},"(exc).",[199,997,998],{"class":341},"__name__",[199,1000,704],{"class":209},[199,1002,1003,1006,1009,1011,1014,1017,1020],{"class":201,"line":475},[199,1004,1005],{"class":304}," \"traceback\"",[199,1007,1008],{"class":209},": traceback.format_exc() ",[199,1010,463],{"class":205},[199,1012,1013],{"class":209}," settings.",[199,1015,1016],{"class":341},"SHOW_TRACEBACKS",[199,1018,1019],{"class":205}," else",[199,1021,367],{"class":341},[199,1023,1024],{"class":201,"line":480},[199,1025,1026],{"class":209}," }\n",[199,1028,1029],{"class":201,"line":517},[199,1030,761],{"class":209},[199,1032,1034],{"class":201,"line":1033},26,[199,1035,278],{"emptyLinePlaceholder":277},[199,1037,1039,1041,1043,1045,1047,1049,1051,1053,1055],{"class":201,"line":1038},27,[199,1040,452],{"class":209},[199,1042,287],{"class":205},[199,1044,457],{"class":341},[199,1046,460],{"class":209},[199,1048,463],{"class":205},[199,1050,1013],{"class":209},[199,1052,1016],{"class":341},[199,1054,1019],{"class":205},[199,1056,1057],{"class":304}," \"Internal server error\"\n",[199,1059,1061,1063],{"class":201,"line":1060},28,[199,1062,520],{"class":205},[199,1064,691],{"class":209},[199,1066,1068,1070,1072,1074],{"class":201,"line":1067},29,[199,1069,696],{"class":491},[199,1071,287],{"class":205},[199,1073,531],{"class":341},[199,1075,704],{"class":209},[199,1077,1079,1081,1083,1086,1088,1090,1092,1094,1096,1098,1100,1102,1104],{"class":201,"line":1078},30,[199,1080,709],{"class":491},[199,1082,287],{"class":205},[199,1084,1085],{"class":209},"ErrorResponse(",[199,1087,166],{"class":491},[199,1089,287],{"class":205},[199,1091,496],{"class":304},[199,1093,429],{"class":209},[199,1095,501],{"class":491},[199,1097,287],{"class":205},[199,1099,506],{"class":209},[199,1101,509],{"class":491},[199,1103,287],{"class":205},[199,1105,1106],{"class":209},"trace_id).model_dump()\n",[199,1108,1110],{"class":201,"line":1109},31,[199,1111,761],{"class":209},[177,1113,1115],{"id":1114},"configuration-environment-overrides","Configuration & Environment Overrides",[162,1117,1118,1119,1122,1123,1126,1127,1130],{},"Externalize handler behavior using environment variables and dependency overrides for deterministic testing. Use ",[166,1120,1121],{},"pydantic-settings"," for environment toggles, mock handlers in ",[166,1124,1125],{},"pytest"," with ",[166,1128,1129],{},"app.dependency_overrides",", and validate configuration on application startup to prevent misconfigured deployments from reaching production.",[190,1132,1134],{"className":192,"code":1133,"language":194,"meta":195,"style":195},"# Startup validation\n@app.on_event(\"startup\")\nasync def validate_config() -> None:\n if settings.APP_ENV == \"production\" and settings.SHOW_TRACEBACKS:\n raise RuntimeError(\"CRITICAL: SHOW_TRACEBACKS must be False in production.\")\n\n# Pytest override pattern\ndef test_exception_override(client: TestClient) -> None:\n async def mock_handler(request: Request, exc: Exception) -> JSONResponse:\n return JSONResponse(status_code=500, content={\"code\": \"TEST_MOCK\", \"detail\": \"mocked\"})\n \n app.dependency_overrides[Exception] = mock_handler\n response = client.get(\"\u002Fforce-error\")\n assert response.status_code == 500\n assert response.json()[\"code\"] == \"TEST_MOCK\"\n",[166,1135,1136,1141,1153,1171,1196,1211,1215,1220,1235,1251,1293,1297,1311,1326,1340],{"__ignoreMap":195},[199,1137,1138],{"class":201,"line":202},[199,1139,1140],{"class":411},"# Startup validation\n",[199,1142,1143,1146,1148,1151],{"class":201,"line":219},[199,1144,1145],{"class":322},"@app.on_event",[199,1147,326],{"class":209},[199,1149,1150],{"class":304},"\"startup\"",[199,1152,308],{"class":209},[199,1154,1155,1157,1159,1162,1165,1168],{"class":201,"line":232},[199,1156,391],{"class":205},[199,1158,394],{"class":205},[199,1160,1161],{"class":322}," validate_config",[199,1163,1164],{"class":209},"() -> ",[199,1166,1167],{"class":341},"None",[199,1169,1170],{"class":209},":\n",[199,1172,1173,1176,1178,1181,1184,1187,1190,1192,1194],{"class":201,"line":245},[199,1174,1175],{"class":205}," if",[199,1177,1013],{"class":209},[199,1179,1180],{"class":341},"APP_ENV",[199,1182,1183],{"class":205}," ==",[199,1185,1186],{"class":304}," \"production\"",[199,1188,1189],{"class":205}," and",[199,1191,1013],{"class":209},[199,1193,1016],{"class":341},[199,1195,1170],{"class":209},[199,1197,1198,1201,1204,1206,1209],{"class":201,"line":258},[199,1199,1200],{"class":205}," raise",[199,1202,1203],{"class":341}," RuntimeError",[199,1205,326],{"class":209},[199,1207,1208],{"class":304},"\"CRITICAL: SHOW_TRACEBACKS must be False in production.\"",[199,1210,308],{"class":209},[199,1212,1213],{"class":201,"line":266},[199,1214,278],{"emptyLinePlaceholder":277},[199,1216,1217],{"class":201,"line":274},[199,1218,1219],{"class":411},"# Pytest override pattern\n",[199,1221,1222,1225,1228,1231,1233],{"class":201,"line":281},[199,1223,1224],{"class":205},"def",[199,1226,1227],{"class":322}," test_exception_override",[199,1229,1230],{"class":209},"(client: TestClient) -> ",[199,1232,1167],{"class":341},[199,1234,1170],{"class":209},[199,1236,1237,1240,1242,1245,1247,1249],{"class":201,"line":293},[199,1238,1239],{"class":205}," async",[199,1241,394],{"class":205},[199,1243,1244],{"class":322}," mock_handler",[199,1246,400],{"class":209},[199,1248,383],{"class":341},[199,1250,405],{"class":209},[199,1252,1253,1255,1257,1259,1261,1263,1265,1267,1269,1272,1275,1277,1280,1282,1285,1287,1290],{"class":201,"line":311},[199,1254,520],{"class":205},[199,1256,523],{"class":209},[199,1258,526],{"class":491},[199,1260,287],{"class":205},[199,1262,531],{"class":341},[199,1264,429],{"class":209},[199,1266,536],{"class":491},[199,1268,287],{"class":205},[199,1270,1271],{"class":209},"{",[199,1273,1274],{"class":304},"\"code\"",[199,1276,846],{"class":209},[199,1278,1279],{"class":304},"\"TEST_MOCK\"",[199,1281,429],{"class":209},[199,1283,1284],{"class":304},"\"detail\"",[199,1286,846],{"class":209},[199,1288,1289],{"class":304},"\"mocked\"",[199,1291,1292],{"class":209},"})\n",[199,1294,1295],{"class":201,"line":316},[199,1296,440],{"class":209},[199,1298,1299,1302,1304,1306,1308],{"class":201,"line":335},[199,1300,1301],{"class":209}," app.dependency_overrides[",[199,1303,383],{"class":341},[199,1305,362],{"class":209},[199,1307,287],{"class":205},[199,1309,1310],{"class":209}," mock_handler\n",[199,1312,1313,1316,1318,1321,1324],{"class":201,"line":345},[199,1314,1315],{"class":209}," response ",[199,1317,287],{"class":205},[199,1319,1320],{"class":209}," client.get(",[199,1322,1323],{"class":304},"\"\u002Fforce-error\"",[199,1325,308],{"class":209},[199,1327,1328,1331,1334,1337],{"class":201,"line":353},[199,1329,1330],{"class":205}," assert",[199,1332,1333],{"class":209}," response.status_code ",[199,1335,1336],{"class":205},"==",[199,1338,1339],{"class":341}," 500\n",[199,1341,1342,1344,1347,1349,1351,1353],{"class":201,"line":370},[199,1343,1330],{"class":205},[199,1345,1346],{"class":209}," response.json()[",[199,1348,1274],{"class":304},[199,1350,362],{"class":209},[199,1352,1336],{"class":205},[199,1354,1355],{"class":304}," \"TEST_MOCK\"\n",[177,1357,1359],{"id":1358},"common-production-mistakes","Common Production Mistakes",[1361,1362,1363,1379],"table",{},[1364,1365,1366],"thead",{},[1367,1368,1369,1373,1376],"tr",{},[1370,1371,1372],"th",{},"Issue",[1370,1374,1375],{},"Root Cause",[1370,1377,1378],{},"Production Fix",[1380,1381,1382,1409,1423],"tbody",{},[1367,1383,1384,1388,1402],{},[1385,1386,1387],"td",{},"Overriding Starlette defaults without preserving request context",[1385,1389,1390,1391,1394,1395,1398,1399,1401],{},"Replacing base handlers strips ",[166,1392,1393],{},"request.state",", causing ",[166,1396,1397],{},"request.url"," and headers to become ",[166,1400,1167],{}," during formatting.",[1385,1403,1404,1405,1408],{},"Always pass ",[166,1406,1407],{},"request: Request"," and extract headers before mutating responses.",[1367,1410,1411,1414,1417],{},[1385,1412,1413],{},"Returning raw Python tracebacks in HTTP responses",[1385,1415,1416],{},"Exposing full stack traces violates security best practices and leaks internal architecture to malicious clients.",[1385,1418,1419,1420,1422],{},"Mask ",[166,1421,501],{}," in production; route raw tracebacks exclusively to structured log sinks.",[1367,1424,1425,1428,1431],{},[1385,1426,1427],{},"Mixing middleware and exception handlers for identical error types",[1385,1429,1430],{},"Middleware executes before exception handlers; catching errors in both layers causes duplicate response mutations and unpredictable status codes.",[1385,1432,1433,1434,1436],{},"Delegate error routing exclusively to ",[166,1435,378],{},"; use middleware only for pre-processing or metrics.",[177,1438,1440],{"id":1439},"faq","FAQ",[162,1442,1443],{},[1444,1445,1446],"strong",{},"Can I register multiple global handlers for the same exception type?",[162,1448,1449],{},"No. FastAPI uses a last-registered-wins approach for duplicate exception types, which causes unpredictable routing and silent handler overrides.",[162,1451,1452],{},[1444,1453,1454],{},"How do I handle Pydantic validation errors globally?",[162,1456,1457,1458,1461,1462,1464,1465,1468],{},"Register an ",[166,1459,1460],{},"@app.exception_handler(RequestValidationError)"," to intercept schema mismatches and return a unified ",[166,1463,701],{}," response using your standardized ",[166,1466,1467],{},"ErrorResponse"," model.",[162,1470,1471],{},[1444,1472,1473],{},"Do global exception handlers impact API latency?",[162,1475,1476],{},"Minimal impact. Handlers execute synchronously or asynchronously only when an error occurs, adding negligible overhead to successful request paths.",[1478,1479,1480],"style",{},"html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sqxcx, html code.shiki .sqxcx{--shiki-default:#E36209}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":195,"searchDepth":219,"depth":219,"links":1482},[1483,1484,1485,1486,1487,1488],{"id":179,"depth":219,"text":180},{"id":544,"depth":219,"text":545},{"id":764,"depth":219,"text":765},{"id":1114,"depth":219,"text":1115},{"id":1358,"depth":219,"text":1359},{"id":1439,"depth":219,"text":1440},"Implementing global exception handlers for consistent API responses eliminates fragmented try\u002Fexcept blocks and guarantees predictable client payloads…","md",{},{"title":123,"description":1489},"v_8ETVFfm7mS5XB4j4iNWckCCwskQ1T9aDC6DMJ8cuI",[1495,1495],null,1778082655320]