exlab_wizard.api.errors#

Error envelope helpers + FastAPI exception handlers. Backend Spec §4.6.3.

Every error response across the API uses the §4.6.3 JSON shape:

{
  "error": {
    "code": "validation_failed",
    "message": "Operator field cannot be empty.",
    "field": "operator",
    "details": { "min_length": 1 },
    "trace_id": "abc123def456"
  }
}

Required: code (stable string identifier; this is what client code branches on), message (human-readable). Optional: field (field-level validation errors), details (free-form structured detail), trace_id (echoed from the request’s X-Trace-Id header if present, else server-generated; correlates with the central app log).

The full code enum table is in §4.6.3; ERROR_CODES mirrors it as a closed string set so adding a new code requires updating both the spec section and this module in the same change.

Functions

build_error_envelope(*, code, message[, ...])

Build the §4.6.3 envelope dict.

error_response(*, request, code, message, ...)

Build a FastAPI JSONResponse carrying the §4.6.3 envelope.

extract_or_create_trace_id(request)

Return the request's X-Trace-Id header, else a fresh hex id.

register_exception_handlers(app)

Attach the §4.6.3 envelope handlers to a FastAPI app.

exlab_wizard.api.errors.build_error_envelope(*, code, message, field=None, details=None, trace_id=None)[source]#

Build the §4.6.3 envelope dict.

code is validated against ERROR_CODES; an unknown code is replaced with "internal_error" and logged at WARN so the client always gets a known discriminator.

Parameters:
Return type:

dict[str, Any]

exlab_wizard.api.errors.error_response(*, request, code, message, status_code, field=None, details=None, extra=None)[source]#

Build a FastAPI JSONResponse carrying the §4.6.3 envelope.

extra is merged into the error block alongside the four standard fields. The setup-incomplete handler uses this to attach state and missing per §4.9.2.

Parameters:
Return type:

JSONResponse

exlab_wizard.api.errors.extract_or_create_trace_id(request)[source]#

Return the request’s X-Trace-Id header, else a fresh hex id.

Server-generated ids use 12 hex characters of cryptographic randomness (secrets.token_hex(6)); plenty of bits for log correlation in a single-user desktop app.

Parameters:

request (Request | None)

Return type:

str

exlab_wizard.api.errors.register_exception_handlers(app)[source]#

Attach the §4.6.3 envelope handlers to a FastAPI app.

Registered in priority order (FastAPI dispatch is most-specific first by isinstance tree; the order below is exhaustive enough that the order at registration is mostly cosmetic).

Each handler is typed against its concrete exception subclass for readability, but Starlette’s add_exception_handler is typed to accept callables over the base Exception – the dispatcher only invokes a handler when the instance matches its registered type, so the per-handler signatures are sound at runtime. We funnel the registrations through _register() so the necessary cast lives in one place.

Parameters:

app (FastAPI)

Return type:

None