{"record":{"id":"a1e43bc84d2a3470","repo":"nats-io/nats-server","slug":"stream-assignment-error-w","errorCode":null,"errorMessage":"stream assignment error: %w","messagePattern":"stream assignment error: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/jetstream_cluster.go","lineNumber":1020,"sourceCode":"\t\treturn nil\n\t}\n\ts, cc := js.srv, js.cluster\n\tif cc == nil {\n\t\t// Non-clustered mode\n\t\tjs.mu.RUnlock()\n\t\treturn nil\n\t}\n\tif sa == nil || sa.Group == nil {\n\t\tjs.mu.RUnlock()\n\t\treturn errors.New(\"stream assignment or group missing\")\n\t}\n\t// Surface any persisted assignment-level error (e.g. failed create on this\n\t// peer due to account limits) so the health check reflects the broken state\n\t// instead of falling through to runtime-only checks.\n\tif sa.err != nil {\n\t\terr := sa.err\n\t\tjs.mu.RUnlock()\n\t\treturn fmt.Errorf(\"stream assignment error: %w\", err)\n\t}\n\tstreamName := sa.Config.Name\n\tnode := sa.Group.node\n\tjs.mu.RUnlock()\n\n\t// First lookup stream and make sure its there.\n\tmset, err := acc.lookupStream(streamName)\n\tif err != nil {\n\t\treturn errors.New(\"stream not found\")\n\t}\n\n\tmsetNode := mset.raftNode()\n\tmset.cfgMu.RLock()\n\treplicas := mset.cfg.Replicas\n\tmset.cfgMu.RUnlock()\n\tvar nrgWerr error\n\tif node != nil {\n\t\tnrgWerr = node.GetWriteErr()","sourceCodeStart":1002,"sourceCodeEnd":1038,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/jetstream_cluster.go#L1002-L1038","documentation":"During a JetStream health check (jsAllStreamsHealthz-style), a stream assignment persisted in the meta layer carries a stored error (sa.err) — e.g. the stream failed to be created on this peer due to account limits. Instead of running runtime-only checks against a broken/absent stream, the health check surfaces this assignment error so the stream reports unhealthy. The message wraps the original cause via %w.","triggerScenarios":"A stream create/update proposal failed on this peer (account limits exceeded, storage unavailable) and the failure was persisted in the assignment; health check runs while a peer's assignment still holds that error; leadership moved to a node that never successfully materialized the stream.","commonSituations":"Account exceeded MaxStreams/MaxBytes so a replica could not create the stream; partial cluster failure during stream creation leaving an error in the assignment; running health checks after a failed migration or scale-up of replicas.","solutions":["Inspect the wrapped cause (errors.Unwrap / %w chain) to find the underlying failure (e.g. account limits) and remediate it (raise limits, free storage)","Check jetstream account limits with the JS API and delete unused streams to make room, then retry the stream creation/update","If the stream is intentionally gone, remove/replace the stale assignment via stream update or API so the meta layer stops carrying the error","Review server logs around the original proposal failure to identify the failing peer and its storage state"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"si, err := js.StreamInfo(streamName)\nif err != nil || si.Cluster == nil { /* stream materialization broken; check account limits and assignment state */ }\n","typeGuard":"func hasAssignmentErr(err error) bool {\n    return strings.Contains(err.Error(), \"stream assignment error\")\n}\n","tryCatchPattern":"if err := healthz(); err != nil {\n    var cause error = errors.Unwrap(err) // dig past \"stream assignment error: %w\"\n    log.Printf(\"stream assignment unhealthy: %v\", cause)\n}\n","preventionTips":["Monitor account limits (MaxStreams, MaxBytes) before creating streams","Check jsz/monitoring output for assignment errors after cluster changes","Remediate the wrapped root cause rather than ignoring health-check failures"],"tags":["jetstream","clustering","health-check","stream-assignment"],"backgroundTag":"jetstream-stream-unhealthy","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}