ADR-006: Structured error hierarchy
Status: Accepted
Date: 2026-02-27
Authors: Anders Hassis
Context
Section titled “Context”Erode interacts with multiple external systems: AI provider APIs, version control platform APIs, file system operations, and architecture model parsers. Each can fail in different ways. Users need clear, actionable error messages. The CLI error handler needs to distinguish between recoverable failures (rate limits) and terminal ones (missing API key).
Generic Error objects do not carry enough context for either need.
Error codes were initially flat identifiers. They were later refactored to use categorized prefixes (CONFIG_*, AUTH_*, etc.) to enable the CLI error handler to format messages differently per category without inspecting error strings (commit 02cf0a5 on 2026-02-27).
Decision
Section titled “Decision”Implement a custom error hierarchy:
ErodeError(base class). Carries anErrorCodeenum value, a user-facing message, a metadata context object, and arecoverableflag.ConfigurationError. For missing or invalid configuration. Always non-recoverable.ApiError. For AI provider HTTP failures. Auto-classifies responses usingclassifyHttpError()to detect rate limiting (429), timeouts (408), and Anthropic-specific acceleration limits. Rate-limited and timed-out errors are marked recoverable.AdapterError. For architecture model loading and querying failures. Carries the adapter type and optional suggestions.
ErrorCode uses categorized prefixes: CONFIG_*, AUTH_*, IO_*, NET_*, PROVIDER_*, PLATFORM_*, MODEL_*, INPUT_*, INTERNAL_*.
Rationale
Section titled “Rationale”Categorized error codes let the CLI error handler format messages differently per category without inspecting error messages. The recoverable flag drives retry logic in the pipeline. ApiError’s HTTP classification means provider-specific retry decisions live in the error class, not scattered across provider implementations.
Static factory methods (fromAnthropicError, fromGeminiError, fromOpenAIError, fromLikeC4Error, fromStructurizrError) standardize error wrapping at system boundaries.
Consequences
Section titled “Consequences”Positive
Section titled “Positive”- Error handling code can branch on
ErrorCodeinstead of parsing messages. - The
recoverableflag centralizes retry decisions. ApiErrordetects rate limits and acceleration limits automatically, providing specific user guidance.- Context metadata aids debugging without exposing internals to users.
Negative
Section titled “Negative”- New error scenarios require adding to the
ErrorCodeenum, which touches the centralerrors.tsfile. - The hierarchy is three levels deep. Adding another subclass level would increase complexity.
Related commits
Section titled “Related commits”8691ba8- chore(release): release 0.4.0 (#24)