ADR-0070: Unified Error Taxonomy and Exception Handling Architecture¶
| Field | Value |
|---|---|
| Status | Accepted (Implemented) |
| Date | 2026-08-12 |
| Authors | Spector Maintainers & Architecture Working Group |
| Deciders | Spector Technical Steering Committee (TSC) |
| Supersedes | None |
| Superseded By | None |
| Last Verified | 2026-09-16 (Verified against main) |
1. Context¶
As Spector evolved from an in-memory research prototype into an off-heap Panama FFM multi-module engine spanning foundation layers (nucleus), cognitive pathways (memory), clustering (cluster), and agentic gateways (synapse), ad-hoc exception throwing (IllegalArgumentException, IllegalStateException, generic RuntimeException) created severe diagnostic ambiguity:
- Callers (REST controllers, CLI tools, MCP clients, and Spring AI vector store integrations) could not programmatically disambiguate between client-recoverable validation errors (e.g., mismatched vector dimensions) and unrecoverable hardware/storage failures (e.g., mmap segmentation faults, unmapped arena access).
- Distributed tracing and telemetry could not categorize errors without brittle string pattern matching on exception messages.
- String formatting overhead in hot execution loops (such as similarity searches scanning 10,000,000 vectors) caused noticeable CPU and heap GC pressure.
A unified, immutable, high-performance error taxonomy was established in nucleus/spector-commons.
2. Problem Statement¶
Error handling in Spector must satisfy four strict operational criteria:
- Machine-Parseable Error Codes: Every failure must carry a stable, unique identifier following a predictable numeric hierarchy across all 27 reactor modules.
- Immutability & Stability Guarantees: Error codes must never be reassigned, renumbered, or deleted once released, ensuring external monitoring, metrics alerting, and enterprise automation never break.
- Zero-Allocation Hot-Path Deferred Formatting: Message formatting with parameters must be deferred using SLF4J-style
{}placeholders so that non-exceptional or intercepted paths incur zero string concatenation overhead. - Hierarchical Typed Exceptions: A clean Java exception hierarchy rooted in
SpectorExceptionallowing callers to catch at subsystem granularity (SpectorMemoryException,SpectorIndexException,SpectorClusterException) or universal scope.
3. Decision Drivers¶
- Developer Experience: Clear, actionable error messages pointing directly to remediation steps or parameter bounds.
- Protocol Interoperability: Direct 1-to-1 mapping from internal error codes to HTTP status codes (RFC 7807 Problem Details), gRPC status codes, and MCP protocol error structures.
- Circuit Breaker Integration: Differentiating transient, retryable failures (e.g.,
EMBEDDING_PROVIDER_TIMEOUT) from permanent validation rejections (DIMENSIONS_MISMATCH).
4. Considered Options¶
Option 1: Standard Java Runtime Exceptions with String Messages¶
- Use
IllegalArgumentException,NoSuchElementException,IllegalStateException. - Verdict: Rejected. Inconsistent messages, zero machine-parseability, breaks internationalization and automated monitoring.
Option 2: Module-Local Error Enums¶
- Each Maven module defines its own error enum (
CoreError,MemoryError,SynapseError). - Verdict: Rejected. Causes number collisions across modules, duplicate error classifications, and prevents a unified REST/gRPC error mapping layer.
Option 3: Centralized SPE-XXX-YYY ErrorCode Enum & Typed Hierarchy (Selected)¶
- A single authoritative enum in
spector-commonscategorizing all error codes into domain blocks with immutable integer values and parameterized message templates. - Verdict: Accepted. Complete diagnostic clarity and zero-overhead deferred string rendering.
5. Decision Outcome¶
Spector standardizes on the ErrorCode enum and SpectorException hierarchy in nucleus/spector-commons.
5.1 Code Schema (SPE-XXX-YYY)¶
Each error code is represented as SPE-XXX-YYY where XXX is the 3-digit subsystem category and YYY is the specific error within that category. Internally, each code is stored as an integer (e.g., 100_001 for SPE-100-001):
graph LR
subgraph Taxonomy ["Error Taxonomy Hierarchy"]
SPE["SPE-XXX-YYY"] --> CAT["Category (XXX)"]
SPE --> ERR["Code (YYY)"]
CAT --> C100["100: VALIDATION"]
CAT --> C200["200: CONFIG"]
CAT --> C300["300: MEMORY"]
CAT --> C400["400: STORAGE"]
CAT --> C500["500: INDEX"]
CAT --> C600["600: CLIENT"]
CAT --> C700["700: SERVER"]
CAT --> C800["800: CLUSTER"]
CAT --> C850["850: CONNECTOR"]
CAT --> C880["880: GPU"]
CAT --> C900["900: INTERNAL"]
end | Category Range | ErrorCategory | Responsibility & Subsystems | HTTP Status |
|---|---|---|---|
SPE-100-xxx | VALIDATION | Vector dimensions, ranges, top-K constraints, null guards | 400 Bad Request |
SPE-200-xxx | CONFIG | Yaml parsing, missing keys, invalid types, environment variables | 500 / 400 |
SPE-300-xxx | MEMORY | Off-heap Panama segment state, arena closed, bundle corrupt | 500 Internal Error |
SPE-400-xxx | STORAGE | File channel open, disk full, WAL truncation, snapshot failures | 500 Internal Error |
SPE-500-xxx | INDEX | HNSW graph corruption, IVF training failure, BM25 tokenization | 500 Internal Error |
SPE-600-xxx | CLIENT | Client SDK timeouts, protocol mismatches, deserialization | 400 / 502 |
SPE-700-xxx | SERVER | REST gateway, Spring AI integration, route dispatch, MCP | 500 / 503 |
SPE-800-xxx | CLUSTER | Cell leasing, fencing tokens, stale routing, raft split-brain | 503 Unavailable |
SPE-850-xxx | CONNECTOR | Apache Camel routes, message ingestion, webhook failure | 502 Bad Gateway |
SPE-880-xxx | GPU | Metal/CUDA driver init, device memory allocation, kernel error | 500 Internal Error |
SPE-900-xxx | INTERNAL | Unreachable code assertions, fatal runtime invariants | 500 Internal Error |
5.2 The SpectorException Class Hierarchy¶
classDiagram
class RuntimeException
class SpectorException {
-errorCode: ErrorCode
-args: Object[]
+getErrorCode() ErrorCode
+getFormattedMessage() String
}
class SpectorValidationException
class SpectorConfigException
class SpectorMemoryException
class SpectorStorageException
class SpectorIndexException
class SpectorClientException
class SpectorServerException
class SpectorClusterException
class SpectorConnectorException
class SpectorGpuException
class SpectorInternalException
RuntimeException <|-- SpectorException
SpectorException <|-- SpectorValidationException
SpectorException <|-- SpectorConfigException
SpectorException <|-- SpectorMemoryException
SpectorException <|-- SpectorStorageException
SpectorException <|-- SpectorIndexException
SpectorException <|-- SpectorClientException
SpectorException <|-- SpectorServerException
SpectorException <|-- SpectorClusterException
SpectorException <|-- SpectorConnectorException
SpectorException <|-- SpectorGpuException
SpectorException <|-- SpectorInternalException 5.3 Deferred Message Formatting Pattern¶
// Definition in ErrorCode.java
DIMENSIONS_MISMATCH(100_002, ErrorCategory.VALIDATION, "Expected {} dimensions but received {}")
// Usage in vector validation: zero heap string concatenation if valid
if (vector.length != expectedDimensions) {
throw new SpectorValidationException(
ErrorCode.DIMENSIONS_MISMATCH,
expectedDimensions,
vector.length
);
}
6. Pros and Cons of the Options¶
Positive¶
- Deterministic Alerting: Infrastructure monitoring (Prometheus/Grafana) binds directly to
errorCode.name()orerrorCode.getCode(). - API Cleanliness: REST controllers and MCP servers cleanly map error codes to RFC 7807 Problem Details without string scraping.
- Zero Drift: A single compilation failure occurs if an error code is renamed or modified incorrectly.
Negative / Trade-offs¶
- Centralized Dependency: All modules throwing domain exceptions depend on
spector-commons(which is already part of the foundation BOM). - Discipline Required: Developers must check
ErrorCode.javabefore adding new errors instead of throwing generic runtime exceptions.
7. Implementation Plan¶
- Centralize all error codes in
com.spectrayan.spector.commons.error.ErrorCode. - Enforce check in unit test
ErrorCodeTestverifying all numeric codes are strictly unique and non-overlapping. - Map error codes in
GlobalExceptionHandlerandAuthExceptionHandlerinspector-synapse.
8. Code Reference & Verification¶
- Central Registry:
nucleus/spector-commons/src/main/java/com/spectrayan/spector/commons/error/ErrorCode.java - Root Exception:
nucleus/spector-commons/src/main/java/com/spectrayan/spector/commons/error/SpectorException.java - Subsystem Exceptions:
nucleus/spector-commons/src/main/java/com/spectrayan/spector/commons/error/ - Unit Verification:
nucleus/spector-commons/src/test/java/com/spectrayan/spector/commons/error/ErrorCodeTest.javaandSpectorExceptionHierarchyTest.java