cadrumo.core.errors.error_codes module¶
Structured error-code registry and CLI rendering helpers.
Centralises Cadrumo’s stable CLI error taxonomy. Every
core.errors.hierarchy.CadrumoError subclass binds to a predeclared
ErrorCode row through bind_error_code(), so the public
contract stays explicit, reviewable, and grep-stable. Rendering helpers
render_error_text() and render_error_json() produce the
human-readable and machine-readable stderr payloads that downstream tools
consume; build_error_envelope() constructs the underlying
ErrorEnvelope.
Secret-looking context keys (matching _SECRET_FIELD_PATTERN) are
redacted before they ever reach stderr — see scrub_error_context().
Non-secret context values are also passed through
core.redaction.rules.redact_for_log() so NIF, URL, and bearer-token
shapes share the same rule vocabulary as logs and observability.
- ERROR_CONTEXT_LABEL_KEYS: Final[tuple[str, ...]]¶
Finite vocabulary translated for human-facing error context labels.
Error contexts themselves remain extensible structured data. Only this declared operator-facing label subset is sent through the locale catalogue; unknown context keys use the same human-readable fallback shape without constructing an unregistered translation key.
- class ErrorCategory(*values)[source]¶
Bases:
StrEnumClosed catalogue of stable CLI error categories.
- ERROR¶
- REFUSED¶
- AUTH¶
- INTEGRITY¶
- FAIL¶
- INTERNAL¶
- LOCKED¶
- class ErrorCode(**data)[source]¶
Bases:
BaseModelStable metadata attached to an
core.errors.hierarchy.CadrumoErrortype.- Parameters:
- code: str¶
- category: ErrorCategory¶
- message_key: str¶
- retryable: bool¶
Whether repeating the IDENTICAL call may succeed with nothing else changed.
True means time alone, or another party finishing, can make the same request work: a held lock, a network failure, a rate limit, a compare-and-swap conflict, a login throttle. False means the call cannot succeed until something else changes – a different argument, an operator action, a state that only another command can create.
This is not decoration. A caller of this CLI may be non-interactive, and this field is the instruction it acts on, so “retryable” on a permanently-failing call is an invitation to loop with no terminating condition. The field carried no stated meaning for a long time, and a refusal for a profile label already bound to a committed capsule inherited
Truefrom a sibling condition that genuinely was a stale-witness conflict; the identical restore could never have succeeded.“Retryable after the operator fixes something” is FALSE by this definition. The agent cannot distinguish it from the transient case, and telling it to retry is what produces the loop.
- public_message_from_registry: bool¶
Ignore positional diagnostic text when rendering a public envelope.
- runbook_id: str | None¶
- class ErrorEnvelope(**data)[source]¶
Bases:
BaseModelMachine-readable error body nested under the shared envelope spine.
Rendered as the
errormember of the stderr error document. The document-level spine (schema_version,command,status,notices) is added byrender_error_json()so the error document and the successcore.json_contract.SchemaEnvelopeshare one outer shape.- Parameters:
- code: str¶
- category: str¶
- message: str¶
- action: ResolvedPreconditionAction | None¶
- retryable: bool¶
- runbook_id: str | None¶
- context: dict[str, str] | None¶
- trace_id: str | None¶
- complete_error_envelope_model()[source]¶
Resolve the canonical action DTO into the envelope model.
ErrorEnvelopenamesResolvedPreconditionAction, which lives incadrumo.core.json_contract. This module cannot import that at definition time: the exception hierarchy binds its codes here while it is still being defined, so reaching forjson_contractfrom module scope re-enters a half-built hierarchy.json_contractcalls this at the bottom of its own module, once both halves exist.build_error_envelope()calls it too, so a caller that never touchesjson_contractstill gets a complete model; it is idempotent and returns immediately when already complete.- Return type:
- register(code)[source]¶
Register
codein the global catalogue.- Parameters:
- Return type:
- Returns:
The same
ErrorCodeobject for fluent use at declaration sites.- Raises:
InternalInvariantError – If a duplicate code identifier is encountered.
- declared_error_codes_by_qualname()[source]¶
Return the declared-code catalogue, loading and registering it on first use.
- get_registered_error_code_by_code(code)[source]¶
Resolve one stable code through the sole declared ErrorCode authority.
- bind_error_code(error_type)[source]¶
Bind a stable
ErrorCodetoerror_type.Called from
CadrumoError.__init_subclass__at class-creation time. Until the declared-code catalogue has been loaded, including while it is loading, the class is added to_DEFERRED_BINDand bound on first use viaget_registered_error_code(); once it is loaded, an undeclared class is refused at creation.- Parameters:
error_type (
type[BaseException]) – Error class being declared.- Return type:
- Returns:
The registered
ErrorCodeforerror_type.- Raises:
InternalInvariantError – When the mapping is available but contains no entry for this class.
- get_registered_error_code(error)[source]¶
Return the registered
ErrorCodeforerror.Loads the declared-code catalogue and drains the deferred binds before the lookup, so classes created before the catalogue loaded are bound here on first use.
- Return type:
- Parameters:
error (BaseException | type[BaseException])
- scrub_error_context(context)[source]¶
Redact secret-looking keys and strip internal keys from
context.Keys matching
_SECRET_FIELD_PATTERNare replaced with"<redacted>". Keys in_INTERNAL_CONTEXT_KEYSare dropped entirely — they are implementation detail (e.g. widget prompt identifiers) and must not appear in operator-facing output.
- build_error_envelope(error, *, action=None, context=None, trace_id=None)[source]¶
Build the deterministic JSON stderr envelope for
error.- Return type:
- Returns:
A frozen
ErrorEnvelopesuitable for serialisation to the machine-readable stderr payload.- Parameters:
error (BaseException)
action (ResolvedPreconditionAction | None)
trace_id (str | None)
- render_error_text(error, *, context=None)[source]¶
Render the human-readable stderr payload for
error.- Return type:
- Parameters:
error (BaseException)
- render_error_json(error, *, action=None, context=None, trace_id=None, active_profile=None, command=None, notices=())[source]¶
Serialize
errorto a deterministic single-line JSON document.The document carries the shared envelope spine (
schema_version,command,active_profile,status,notices) so it is shape-compatible with the successcore.json_contract.SchemaEnvelope. The error detail is nested undererror.commandis the dotted identifier of the command that failed (byte-identical to thecommand=its success envelope would emit), resolved by the CLI boundary from the live click context and passed here; it isNoneonly when no command has resolved yet — an argv parse failure before dispatch, or a direct render without a command. Thecorelayer never touches the click context, so the CLI boundary resolves the identifier and passes it.active_profileis the human label of the active taxpayer profile (the identity anchor),Nonefor a non-profile-bound failure or when the CLI error boundary cannot resolve it; thecorelayer never scans profile manifests, so the CLI boundary resolves the label and passes it here.noticescarries the same typed diagnostics the success envelope’snoticeschannel does — the sandbox-active indicator above all, so a failure inside a discardable sandbox bucket is distinguishable from the same failure against the operator’s real profile.corenever resolves them for the same reason it never resolvesactive_profile: it may not scan buckets.statusstaysEnvelopeStatus.ERRORregardless of notice severity — this document reports a failure, and no notice can soften that. Thecore.json_contract.ENVELOPE_SCHEMA_VERSIONimport is function-local to avoid thejson_contract<->errorsimport cycle (json_contractimportsCadrumoError).
- get_error_exit_code(category)[source]¶
Return the canonical process exit code for
category.The exit-code family is the operator’s coarse outcome signal:
ERROR-> 1: an expected, operator-actionable failure or refusal of a domain outcome. A modelo verification that resolves not-granted — whetherBLOCKED(a blocking-rule finding) orINCOMPLETE(missing required casillas) — exits 1: both are expected verification verdicts, surfaced throughtyper.Exit(code=1)in the verify handler, never as anINTERNALcrash.REFUSED-> 2,AUTH-> 3,INTEGRITY-> 4,FAIL-> 5,LOCKED-> 7: the remaining expected, registered refusal classes.INTERNAL-> 6 is reserved exclusively for an unexpected internal crash (theINTERNAL_*registry codes:INTERNAL_CLI_UNEXPECTED_BOUNDARY,INTERNAL_WORKFLOW_UNHANDLED, etc.). An expected domain outcome MUST NOT map toINTERNAL— a not-granted verification verdict is a result the operator must act on, not a program defect, so it never exits 6.
- Return type:
- Parameters:
category (ErrorCategory)
- resolve_error_message(error, code=None, *, locale=None)[source]¶
Resolve the user-facing message for
error.translated_messageis a translation key (e.g."profile.errors.not_configured") by convention; it is rendered through the i18n backend, which falls back to the key itself when no matching translation exists.- Return type:
- Parameters:
error (BaseException)
code (ErrorCode | None)
locale (str | None)