nats-io/nats-server · error

failed to activate stream %q: %w

Error message

failed to activate stream %q: %w

What it means

When the restore payload finishes, the deferred completeRestore() call flips the stream from restore mode to fully active (sealing state, publishing internal notices, switching the store). If that activation fails, the error is wrapped as 'failed to activate stream' and becomes the restore's return error, while a warning is logged. Messages may have been written but the stream is left incomplete/unusable.

Source

Thrown at server/stream_backup.go:381

	if err != nil {
		return nil, err
	}
	if err := checkUsageLimits(); err != nil {
		return nil, err
	}

	mset, err := a.addStreamForRestore(&cfg)
	if err != nil {
		return nil, fmt.Errorf("error adding stream: %w", err)
	}
	defer func() {
		var state StreamState
		mset.store.FastState(&state)
		mset.mu.Lock()
		mset.lseq = state.LastSeq
		mset.mu.Unlock()
		if err := mset.completeRestore(); err != nil {
			if err = fmt.Errorf("failed to activate stream %q: %w", cfg.Name, err); retErr == nil {
				retErr = err
			}
			s.Warnf("JetStream stream restore for '%s > %s' failed to activate stream: %v", a.Name, cfg.Name, err)
		}
	}()

	// Start off at the right sequence number. This is important in particular
	// when the backup contains no messages or would restore to no interest.
	if _, err = mset.store.Compact(nstate.FirstSeq); err != nil {
		return nil, fmt.Errorf("error purging stream: %w", err)
	}

	var restoredConsumers, ephemerals []*consumer
	defer func() {
		// Consumers must be unconditionally converted and completed, otherwise
		// a partial restore that fails midway through can leave assets that are
		// unusable.
		for _, o := range ephemerals {

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Check the server log line 'failed to activate stream' for the wrapped cause (store/IO vs cluster)
  2. Free disk space / fix store directory permissions, then delete the partially restored stream and re-run the restore
  3. In clustered mode, ensure a quorum is healthy before retrying the restore
  4. If the stream exists but is unusable after a failed activation, delete it (`nats stream rm`) and restore again

Example fix

// before: blind retry after activation failure
acc.RestoreStreamV2(cfg, r)
// after: clean up the half-activated stream, then retry
if _, err := acc.RestoreStreamV2(cfg, r); err != nil {
    if strings.Contains(err.Error(), "failed to activate stream") {
        jsDeleteStream(account, cfg.Name) // remove unusable partial stream
        return acc.RestoreStreamV2(cfg, freshReader())
    }
    return err
}
Defensive patterns

Strategy: retry

Validate before calling

// ensure cluster quorum and disk headroom before restoring
if !jsClusterHealthy() || freeDisk(storeDir) < snapshotBytes*2 {
    return fmt.Errorf("preconditions for stream activation not met")
}

Try / catch

mset, err := acc.RestoreStreamV2(cfg, r)
if err != nil {
    if strings.Contains(err.Error(), "failed to activate stream") {
        jsDeleteStream(account, cfg.Name) // remove unusable partial stream
        time.Sleep(backoff)
        return acc.RestoreStreamV2(cfg, freshReader()) // bounded retry
    }
    return err
}

Prevention

When it happens

Trigger: mset.completeRestore() returns an error: typically the underlying store's activation step fails (file-system error persisting final state), the stream was somehow invalidated mid-restore, or cluster/Raft metadata update for the restored stream fails in clustered mode.

Common situations: Disk full or I/O error on the JetStream store during the final state write; server shutting down mid-restore; cluster member failing while updating stream assignment; storage backend bug when re-opening a restored stream for publishing.

Related errors


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