gofr-dev/gofr · error
handler error
Error message
handler error
What it means
errHandlerError (errors.go:20) is the sentinel used in the NATS client's message-fetch/consume path when the registered message handler fails or fetching the next message errors. It wraps handler failures so the consume loop can report them through Query/subscriber error handling. Exercised by TestClient_Query_MessageFetchError.
Source
Thrown at pkg/gofr/datasource/pubsub/nats/errors.go:20
import "errors"
var (
// Client Errors.
errServerNotProvided = errors.New("client server address not provided")
errSubjectsNotProvided = errors.New("subjects not provided")
errConsumerNotProvided = errors.New("consumer name not provided")
errConsumerCreationError = errors.New("consumer creation error")
errFailedToDeleteStream = errors.New("failed to delete stream")
errPublishError = errors.New("publish error")
errJetStreamNotConfigured = errors.New("jStream is not configured")
errJetStreamCreationFailed = errors.New("jStream creation failed")
errJetStream = errors.New("jStream error")
errCreateStream = errors.New("create stream error")
errDeleteStream = errors.New("delete stream error")
errGetStream = errors.New("get stream error")
errCreateOrUpdateStream = errors.New("create or update stream error")
errHandlerError = errors.New("handler error")
errConnectionError = errors.New("connection error")
errSubscriptionError = errors.New("subscription error")
)
View on GitHub (pinned to 187eb24962)
Solutions
- Make your message handler defensive: validate/decode payloads and return errors only for genuine failures.
- Check the wrapped cause to distinguish a handler bug from a fetch/consumer failure.
- Recreate or reset the consumer if it was deleted or detached server-side (`nats consumer info <stream> <consumer>`).
- Add dead-letter/NAK handling for poison messages instead of failing the loop repeatedly.
Example fix
// before: handler errors on bad payload
handler := func(ctx context.Context, m pubsub.Message) error {
var o Order; return json.Unmarshal(m.Value(), &o)
}
// after: tolerate malformed messages
if err := json.Unmarshal(m.Value(), &o); err != nil {
logger.Errorf("skipping malformed message: %v", err)
return nil
} Defensive patterns
Strategy: try-catch
Validate before calling
// validate handler behavior before registering
if handler == nil {
return errors.New("message handler must not be nil")
} Try / catch
handler := func(ctx context.Context, m pubsub.Message) error {
defer func() {
if r := recover(); r != nil {
logger.Errorf("handler panic: %v", r)
}
}()
return process(ctx, m)
} Prevention
- Validate/decode payloads inside the handler; return nil for poison messages after logging.
- Recover from panics in the handler so one bad message doesn't kill consumption.
- Monitor consumer state (`nats consumer info`) for detached/deleted consumers.
- Set sensible AckWait/MaxDeliver and dead-letter flows for redelivery storms.
When it happens
Trigger: During Client.Query/subscription consumption: the user-supplied MessageHandler returns an error, or fetching a message from the JetStream consumer fails (message expired/deleted, consumer detached).
Common situations: Handler panics or returns errors on malformed payloads (JSON decode failures); messages redelivered after AckWait with consumers in a bad state; consumer deleted server-side while fetching.
Related errors
AI-assisted analysis of gofr-dev/gofr@187eb24962 (2026-09-01).
Data as JSON: /api/errors/15668cee9d2e79bc.
Report an issue: GitHub.