{"id":"19d3c53225d4536f","repo":"tiangolo/fastapi","slug":"oops-exc-name-did-something-there-goes-a-rainb","errorCode":null,"errorMessage":"Oops! {exc.name} did something. There goes a rainbow...","messagePattern":"Oops! (.+?) did something\\. There goes a rainbow\\.\\.\\.","errorType":"http","errorClass":"UnicornException","httpStatus":418,"severity":"warning","filePath":"docs_src/handling_errors/tutorial003_py310.py","lineNumber":24,"sourceCode":"    def __init__(self, name: str):\n        self.name = name\n\n\napp = FastAPI()\n\n\n@app.exception_handler(UnicornException)\nasync def unicorn_exception_handler(request: Request, exc: UnicornException):\n    return JSONResponse(\n        status_code=418,\n        content={\"message\": f\"Oops! {exc.name} did something. There goes a rainbow...\"},\n    )\n\n\n@app.get(\"/unicorns/{name}\")\nasync def read_unicorn(name: str):\n    if name == \"yolo\":\n        raise UnicornException(name=name)\n    return {\"unicorn_name\": name}\n","sourceCodeStart":6,"sourceCodeEnd":26,"githubUrl":"https://github.com/tiangolo/fastapi/blob/42a41db11f6882807ac3c057b942178d53b97438/docs_src/handling_errors/tutorial003_py310.py#L6-L26","documentation":"Raising the custom UnicornException (carrying name=\"yolo\") triggers the registered `@app.exception_handler(UnicornException)`, which returns HTTP 418 with body {\"message\": \"Oops! yolo did something. There goes a rainbow...\"}. The message is generated by the handler from exc.name, not by HTTPException, demonstrating FastAPI's custom-exception-handler mechanism.","triggerScenarios":"GET /unicorns/yolo specifically; any other name returns 200 with the echo body.","commonSituations":"Clients/probes hitting the reserved name; reusing the UnicornException pattern for real domain errors; forgetting to register an exception_handler so the exception surfaces as 500.","solutions":["Avoid the name \"yolo\", or accept the 418 if that is the intended demo behavior.","If adapting to real use, register a handler that returns a meaningful status code (e.g. 400) instead of 418.","Ensure every custom exception your app raises has a registered handler.","Add a test asserting the 418 body shape for /unicorns/yolo."],"exampleFix":"# before\nif name == \"yolo\":\n    raise UnicornException(name=name)\n\n# after (domain-aware)\nif name in FORBIDDEN_NAMES:\n    raise UnicornException(name=name)","handlingStrategy":"validation","validationCode":"if name == \"yolo\":\n    raise ValueError(\"name 'yolo' is rejected by /unicorns\")","typeGuard":"def is_allowed_unicorn(name: str) -> bool:\n    return name != \"yolo\"","tryCatchPattern":"r = client.get(f\"/unicorns/{name}\")\nif r.status_code == 418:\n    msg = r.json().get(\"message\", \"\")\n    if \"There goes a rainbow\" in msg:\n        # reserved name hit; choose another\n        ...","preventionTips":["Block reserved names client-side.","Register a handler for every custom exception you raise.","Treat 418 as a domain error, not a transport error."],"tags":["fastapi","custom-exception","exception-handler","http-418","handling-errors"],"analyzedSha":"42a41db11f6882807ac3c057b942178d53b97438","analyzedAt":"2026-08-04T19:23:32.007Z","schemaVersion":2}