nats-io/nats-server · error

undefined message handler

Error message

undefined message handler

What it means

errInvalidMsgHandler: aSubscribe/subscribe was invoked with a nil message callback — the internal client cannot deliver messages without a handler, so the subscription request is rejected before creation.

Source

Thrown at server/stream.go:6376

		// to prevent a trace event to be generated when a stored message
		// is delivered to a consumer and routed.
		if !traceOnly {
			hdr = setHeader(MsgTraceDest, MsgTraceDestDisabled, hdr)
		}
		// This will add the jetstream event while in the client read loop.
		// Since the event will be updated in a different go routine, the
		// tracing object will have a separate reference to the JS trace
		// object.
		mt.addJetStreamEvent(mset.name())
	}
	mset.queueInbound(mset.msgs, subject, reply, hdr, msg, nil, c.pa.trace)
}

var (
	errLastSeqMismatch   = errors.New("last sequence mismatch")
	errMsgIdDuplicate    = errors.New("msgid is duplicate")
	errStreamClosed      = errors.New("stream closed")
	errInvalidMsgHandler = errors.New("undefined message handler")
	errStreamMismatch    = errors.New("expected stream does not match")
	errMsgTTLDisabled    = errors.New("message TTL disabled")
)

// processJetStreamMsg is where we try to actually process the stream msg.
// needIsolation should be false only if the caller already holds isolateMu
// across a whole atomic batch; mset.mu must NOT be held by the caller.
func (mset *stream) processJetStreamMsg(subject, reply string, hdr, msg []byte, lseq uint64, ts int64, mt *msgTrace, sourced bool, needIsolation bool) error {
	return mset.processJetStreamMsgWithBatch(subject, reply, hdr, msg, lseq, ts, mt, sourced, needIsolation, nil)
}

func (mset *stream) processJetStreamMsgWithBatch(subject, reply string, hdr, msg []byte, lseq uint64, ts int64, mt *msgTrace, sourced bool, needIsolation bool, fastBatch *FastBatch) (retErr error) {
	if mt != nil {
		// Only the leader/standalone will have mt!=nil. On exit, send the
		// message trace event.
		defer func() {
			mt.sendEventFromJetStream(retErr)
		}()

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Pass a non-nil callback when subscribing
  2. Use a channel-based subscription API if a func cannot be provided
Defensive patterns

Strategy: type-guard

When it happens

Trigger: Thrown at server/stream.go:6376 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/6fa26e46103cf239. Report an issue: GitHub.