Terminal error formatting for chirp development server.
Provides structured, human-readable error output for the terminal during
chirp run. Replaces raw logger.exception()with clean diagnostics
that highlight the useful information.
For startup errors:
Maps known startup exceptions (port conflicts, TLS misconfiguration,
lifespan failures, config validation) to clean, actionable messages
via ``format_startup_error()``. Returns ``None`` for unrecognised
errors so the caller can fall back to the default traceback.
For Kida template errors:
Calls ``exc.format_compact()`` and adds Chirp-specific context (route,
method, path). Produces output like::
-- Template Error -----------------------------------------------
K-RUN-001: Undefined variable 'usernme' in base.html:42
|
>42 | <h1>{{ usernme }}</h1>
|
Route: GET /dashboard
Hint: Use {{ usernme | default('') }} for optional variables
Docs: https://kida.dev/docs/errors/#k-run-001
-----------------------------------------------------------------
For non-template errors:
Uses configurable traceback verbosity (compact/full/minimal) controlled
by theCHIRP_TRACEBACKenvironment variable.
server.terminal_errors
| Name | Type | Default | Description |
|---|---|---|---|
type
|
|
— | |
qualified_name
|
|
— | |
element_type
|
|
— | |
description
|
|
— | |
source_file
|
|
— | |
line_number
|
|
— | |
is_autodoc
|
|
— | |
autodoc_element
|
|
— | |
_autodoc_template
|
|
— | |
_autodoc_url_path
|
|
— | |
_autodoc_page_type
|
|
— | |
title
|
|
— | |
doc_content_hash
|
|
— |
Symbols on this page
Check if an exception originates from the kida template engine.
Error message safe for HTTP/SSE/JSON (no ANSI codes).
Error message safe for HTML display (no ANSI escape codes).
When structured_panelis True, the debug page renders source snippets, stacks, and hints separately…
True if the frame is from the application (not stdlib/site-packages).
Format a Kida template error for logging (plain text, no ANSI).
Uses the same compact body as_plain_error_message() — Kida's
format_compact()with ANSI…
Format a non-template error with compact traceback.
Shows only application frames + error summary, suppressing framework internals from kida, starlette, uvicorn, anyio.
One-line error summary for minimal verbosity.
True when exc signals the client closed the connection mid-response.
Long-lived streaming/SSE responses routinely end with the peer vanishing — a browser tab closes,…
Log an internal error with appropriate formatting.
Detects Kida template errors and formats them cleanly. For non-template errors, uses the traceback verbosity level from …
Map a startup exception to a clean, actionable terminal message.
Append__cause__context when present (e.g. LifespanError wrapping a DB error).
_is_kida_error
function
def _is_kida_error(exc: BaseException) -> bool
Check if an exception originates from the kida template engine.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
exc
|
BaseException
|
— |
_plain_error_message
function
def _plain_error_message(exc: BaseException) -> str
Error message safe for HTTP/SSE/JSON (no ANSI codes).
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
exc
|
BaseException
|
— |
_html_error_message
function
def _html_error_message(exc: BaseException, *, structured_panel: bool = False) -> str
Error message safe for HTML display (no ANSI escape codes).
When structured_panel is True, the debug page renders source snippets,
stacks, and hints separately — so return a one-line summary instead of
format_compact()'s full terminal-style block.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
exc
|
BaseException
|
— | |
structured_panel
|
bool
|
False
|
_is_app_frame
function
def _is_app_frame(filename: str) -> bool
True if the frame is from the application (not stdlib/site-packages).
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
filename
|
str
|
— |
format_template_error
function
def format_template_error(exc: BaseException, request: Request | None = None) -> str
Format a Kida template error for logging (plain text, no ANSI).
Uses the same compact body as_plain_error_message() — Kida's
format_compact()with ANSI stripped so JSON/structured logs stay readable.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
exc
|
BaseException
|
— | A Kida template exception (TemplateError subclass). |
request
|
Request | None
|
None
|
The request that triggered the error (optional). |
format_compact_traceback
function
def format_compact_traceback(exc: BaseException) -> str
Format a non-template error with compact traceback.
Shows only application frames + error summary, suppressing framework internals from kida, starlette, uvicorn, anyio.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
exc
|
BaseException
|
— | Any exception. |
format_minimal_error
function
def format_minimal_error(exc: BaseException) -> str
One-line error summary for minimal verbosity.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
exc
|
BaseException
|
— | Any exception. |
is_client_disconnect
function
def is_client_disconnect(exc: BaseException) -> bool
True when exc signals the client closed the connection mid-response.
Long-lived streaming/SSE responses routinely end with the peer vanishing — a
browser tab closes, a proxy times the idle connection out — which surfaces in
the server's send/drain path as a TCP reset or broken pipe. These are not
server faults: there is nothing left to send and nothing to alert on. Callers
log them atDEBUGand skip the 500 error path (see
handle_sse() and
send_streaming_response()).
Covers the peer-gone classes (ConnectionResetError / BrokenPipeError/
ConnectionAbortedError) plus a bare OSErrorcarrying a disconnect
errno (ECONNRESET / EPIPE / ECONNABORTED).
Deliberately narrower thanConnectionError: the broad exceptblocks
that call this also wrap the user's stream generator body, so a generic
ConnectionError — most notably ConnectionRefusedError (ECONNREFUSED,
an outbound failure when the generator's own upstream DB/cache/HTTP target
refuses) — is a genuine server error that must stay loud, not be swallowed as
a benign client disconnect.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
exc
|
BaseException
|
— |
log_error
function
def log_error(exc: BaseException, request: Request | None = None) -> None
Log an internal error with appropriate formatting.
Detects Kida template errors and formats them cleanly. For non-template
errors, uses the traceback verbosity level fromCHIRP_TRACEBACK
(compact, full, minimal). Defaults to compact.
This replaces the rawlogger.exception()call in
handle_internal_error().
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
exc
|
BaseException
|
— | The exception that caused the 500 error. |
request
|
Request | None
|
None
|
The request that triggered the error (optional for streaming/SSE contexts where a request may not be available). |
format_startup_error
function
def format_startup_error(exc: BaseException, *, cli: bool = False) -> str | None
Map a startup exception to a clean, actionable terminal message.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
exc
|
BaseException
|
— | The exception raised during startup. |
cli
|
bool
|
False
|
When ``True``, hints reference ``chirp run --port`` instead of ``app.run(port=...)``. Returns ``None`` if the exception is not a recognised startup error (caller should re-raise or fall back to default handling). |
_with_cause
function
def _with_cause(msg: str, exc: BaseException) -> str
Append__cause__context when present (e.g. LifespanError wrapping a DB error).
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
msg
|
str
|
— | |
exc
|
BaseException
|
— |
View source · /home/runner/work/chirp/chirp/site/../src/chirp/server/terminal_errors.py:1