nats-io/nats-server · warning

stream missing

Error message

stream missing

What it means

This error is produced by jetStream.isConsumerHealthy, the JetStream health-check routine that verifies each consumer is present and healthy on this server. It means the health check was invoked for a consumer whose parent stream (*stream) is nil on this server, so the consumer cannot even be looked up. In practice this indicates the server is being asked to report health for a consumer whose stream no longer exists (or has not yet materialized) locally, typically transiently during cluster topology changes or shutdown.

Source

Thrown at server/jetstream_cluster.go:1086

	case !node.Healthy():
		return errors.New("group node unhealthy")

	default:
		return nil
	}
}

// isConsumerHealthy will determine if the consumer is up to date.
// For R1 it will make sure the consunmer is present on this server.
func (js *jetStream) isConsumerHealthy(mset *stream, consumer string, ca *consumerAssignment) error {
	js.mu.RLock()
	if ca != nil && ca.unsupported != nil {
		js.mu.RUnlock()
		return nil
	}
	if mset == nil {
		js.mu.RUnlock()
		return errors.New("stream missing")
	}
	s, cc := js.srv, js.cluster
	if cc == nil {
		// Non-clustered mode
		js.mu.RUnlock()
		return nil
	}
	if ca == nil || ca.Group == nil {
		js.mu.RUnlock()
		return errors.New("consumer assignment or group missing")
	}
	// Surface any persisted assignment-level error (e.g. failed create on this
	// peer) so the health check reflects the broken state instead of falling
	// through to runtime-only checks.
	if ca.err != nil {
		err := ca.err
		js.mu.RUnlock()
		return fmt.Errorf("consumer assignment error: %w", err)

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Check whether the stream was deleted or renamed; recreate the stream if it should exist.
  2. Treat it as transient during cluster reconfiguration: wait for the assignment to settle and re-run the health check.
  3. Check server logs for stream deletion/creation events around the error time to identify the racing operation.
  4. If persistent, restart the server so JetStream recovers assignments from the meta layer, or file an issue if it never clears.

Example fix

// before: health check errors while stream is not yet materialized
// after: gate the health check on stream presence / retry after replication
if mset == nil {
    if time.Since(ca.Created) < 5*time.Second {
        return nil // stream not materialized yet, give it time
    }
    return errors.New("stream missing")
}
Defensive patterns

Strategy: retry

Validate before calling

// Verify stream exists before trusting/acting on health output
st, err := js.StreamInfo(streamName)
if err != nil || st == nil {
    // stream missing locally; wait for replication or recreate
}

Try / catch

// Go: treat as transient during topology changes
if err := srvHealth(ctx); err != nil {
    if strings.Contains(err.Error(), "stream missing") {
        time.Sleep(2 * time.Second)
        return retryHealth(ctx)
    }
    return err
}

Prevention

When it happens

Trigger: Health check (/jsz HEALTH or monitor endpoint) iterates assignments and calls isConsumerHealthy while mset (the local stream) is nil for that assignment — e.g. the stream was deleted or its assignment exists but the local stream object has not been created yet during meta/asset replication, or a race during server shutdown.

Common situations: NATS servers running with -js_enable_health_check (or /jsz?health=true) reporting 'stream missing' during rolling restarts; stream deletion racing a periodic health check; a new server joining the cluster and being probed before its stream assets materialize.

Related errors


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