A lightweight, production-ready exception handling framework for Spring applications with first-class support for HTTP APIs, OpenFeign, Kafka, distributed tracing, retry-aware error propagation, and standardized error contracts.
nerv-exception provides a consistent failure model across synchronous and asynchronous communication channels while remaining framework-agnostic at its core.
Most distributed systems suffer from inconsistent error handling:
- Different services return different error payloads
- Retry behavior is undocumented
- Feign clients lose downstream context
- Kafka failures are difficult to correlate
- Trace information is not consistently exposed
- Error codes are scattered across services
NERV Exception solves these problems through a unified error contract built around NervErrorCode.
- Centralized exception handling
- Strongly typed application error codes
- Standardized error responses
- Retry-aware error contracts
- Error categorization
- Extensible architecture
- Framework-agnostic core API
- Automatic MVC exception handling
- Consistent HTTP error payloads
- Automatic status mapping
- Distributed trace exposure
- Automatic error decoding
- Retry-aware exception conversion
- Downstream error preservation
- Custom error code registries
- Structured error events
- Dead-letter queue publishing
- Trace-aware error propagation
- Kafka header mapping
- Micrometer Tracing integration
- OpenTelemetry integration
- Distributed trace support
- Span-aware diagnostics
- Zero-configuration setup
- Auto-configuration
- Conditional integrations
- No component scanning
HTTP Request
↓
NervException
↓
NervExceptionHandler
↓
NervErrorResponse
↓
Feign
↓
NervFeignErrorDecoder
↓
RetryableException / NervDownstreamException
↓
Kafka
↓
NervErrorEvent
↓
DLQ
| Module | Description |
|---|---|
nerv-exception-api |
Core contracts and abstractions |
nerv-exception-core |
Base exceptions, mappers, native error codes |
nerv-exception-spring-web |
Spring MVC integration |
nerv-exception-spring-feign |
OpenFeign integration |
nerv-exception-event |
Error event model and event mapping |
nerv-exception-spring-kafka |
Kafka integration and DLQ publishing |
nerv-exception-spring-boot-starter |
Auto-configuration |
starter
├─ spring-web
│ └─ core
│ └─ api
│
├─ spring-feign
│ └─ core
│ └─ api
│
└─ spring-kafka
└─ event
└─ core
└─ api
NERV Exception never relies on package scanning.
No:
@EnableNervExceptionis required.
All beans are created through:
NervExceptionAutoConfigurationFeign, Kafka, and tracing support activate only when their dependencies are available.
Retryability belongs to the error code itself.
Tracing is provided by Micrometer/OpenTelemetry.
NERV Exception consumes trace information but does not implement a tracing system.
<dependency>
<groupId>com.czetsuyatech</groupId>
<artifactId>nerv-exception-spring-boot-starter</artifactId>
<version>${nerv-exception.version}</version>
</dependency>public enum PaymentErrorCode implements NervErrorCode {
PAYMENT_TIMEOUT(
"PAYMENT_TIMEOUT",
"Payment provider timed out",
504,
true,
"INTEGRATION"
),
PAYMENT_NOT_FOUND(
"PAYMENT_NOT_FOUND",
"Payment not found",
404,
false,
"BUSINESS"
);
}throw new NervException(PaymentErrorCode.PAYMENT_TIMEOUT);{
"code": "PAYMENT_TIMEOUT",
"message": "Payment provider timed out",
"status": 504,
"retryable": true,
"category": "INTEGRATION",
"traceId": "0af7651916cd43dd8448eb211c80319c",
"spanId": "b9c7c989f97918e1",
"path": "/payments/timeout",
"timestamp": "2026-06-23T00:00:00Z"
}The entire framework revolves around a single abstraction:
public interface NervErrorCode {
String code();
String message();
int status();
boolean retryable();
String category();
}Every error in the system derives from this contract.
Enable:
nerv:
exception:
web:
enabled: trueFeatures:
- Global exception handling
- Automatic status mapping
- Standardized responses
- Trace-aware diagnostics
No additional configuration is required.
Enable:
nerv:
exception:
feign:
enabled: trueFeatures:
- Automatic error decoding
- Retry-aware exception conversion
- Custom error code resolution
- Downstream error preservation
When a downstream service returns:
{
"code": "PAYMENT_TIMEOUT",
"retryable": true
}NervFeignErrorDecoder automatically converts the response into:
RetryableExceptionallowing retry frameworks such as:
- Resilience4j
- Spring Retry
- Feign Retryer
to retry the request.
Non-retryable errors become:
NervDownstreamExceptionRemote failures preserve:
- traceId
- spanId
- timestamp
- path
- details
allowing easier troubleshooting across service boundaries.
Applications can register custom error code enums.
@Bean
NervErrorCodeRegistry applicationErrorCodeRegistry() {
return new EnumNervErrorCodeRegistry(
PaymentErrorCode.values(),
CustomerErrorCode.values(),
OrderErrorCode.values()
);
}Resolution order:
Application Registry
↓
Native Registry
Duplicate error codes are detected during startup.
Enable:
nerv:
exception:
kafka:
enabled: true
source: payment-service
dlq-topic-suffix: .dlqFeatures:
- Structured error events
- Dead-letter publishing
- Kafka header mapping
- Trace-aware diagnostics
{
"code": "PAYMENT_TIMEOUT",
"message": "Payment provider timed out",
"category": "INTEGRATION",
"retryable": true,
"source": "payment-service",
"traceId": "0af7651916cd43dd8448eb211c80319c",
"spanId": "b9c7c989f97918e1",
"parentEventId": "payment-timeout-failed",
"timestamp": "2026-06-23T00:00:00Z"
}| Header | Description |
|---|---|
nerv-trace-id |
Trace identifier |
nerv-span-id |
Span identifier |
nerv-source |
Originating service |
nerv-parent-event-id |
Parent event identifier |
nerv-error-code |
Error code |
nerv-error-category |
Error category |
NERV Exception integrates with Micrometer Tracing.
Supported providers include:
- OpenTelemetry
- Brave
- Custom Micrometer implementations
Tracing is exposed through:
public interface NervTraceContextResolver {
NervTraceContext current();
}Default implementation:
MicrometerNervTraceContextResolverFallback:
NoOpNervTraceContextResolverRecommended dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-opentelemetry</artifactId>
</dependency>Propagation uses standard OpenTelemetry headers:
traceparent
tracestate
No custom propagation configuration is required.
| Contract | Purpose |
|---|---|
NervErrorCode |
Application error codes |
NervErrorCodeRegistry |
Remote error code resolution |
NervTraceContextResolver |
Distributed tracing integration |
NervEventTraceContextResolver |
Event tracing integration |
- Java 21+
- Spring Boot 4.x
Optional:
- OpenFeign
- Apache Kafka
- Micrometer Tracing
- OpenTelemetry
Apache License 2.0