{"record":{"id":"175468ff554c8e4b","repo":"nats-io/nats-server","slug":"restore-for-stream-s-s-is-stalled","errorCode":null,"errorMessage":"restore for stream '%s > %s' is stalled","messagePattern":"restore for stream '(.+?) > (.+?)' is stalled","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/jetstream_api.go","lineNumber":4434,"sourceCode":"\t\t\t\trestoreDone = true\n\t\t\t\trestoreResult = rr\n\t\t\t\tif inputDone {\n\t\t\t\t\terr := inputErr\n\t\t\t\t\tif err == nil {\n\t\t\t\t\t\terr = rr.err\n\t\t\t\t\t}\n\t\t\t\t\tfinish(replySubj, err, rr.mset)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tcase <-activeQ.ch:\n\t\t\t\tif n, ok := activeQ.popOne(); ok {\n\t\t\t\t\ttotal += n\n\t\t\t\t\tif !inputDone {\n\t\t\t\t\t\tnotActive.Reset(activityInterval)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tcase <-notActive.C:\n\t\t\t\terr := fmt.Errorf(\"restore for stream '%s > %s' is stalled\", acc.Name, streamName)\n\t\t\t\tcloseWithError(err)\n\t\t\t\tdoneCh <- err\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t})\n\n\treturn doneCh\n}\n\n// Process a snapshot request.\nfunc (s *Server) jsStreamSnapshotRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) {\n\tif c == nil || !s.JetStreamEnabled() {\n\t\treturn\n\t}\n\tci, acc, hdr, msg, err := s.getRequestInfo(c, rmsg)\n\tif err != nil {\n\t\ts.Warnf(badAPIRequestT, msg)","sourceCodeStart":4416,"sourceCodeEnd":4452,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/jetstream_api.go#L4416-L4452","documentation":"JetStream stream restore inactivity timeout. During a restore the server arms an activity timer; if no new chunk arrives within the interval, the restore is considered stalled and is cancelled with this error.","triggerScenarios":"Client stops sending chunks (crash, slow producer, network partition) without closing the restore session, leaving the notActive timer to fire after activityInterval.","commonSituations":"Client application killed mid-restore; WAN/slow link where chunk generation takes longer than the inactivity window; back-pressure from client-side file reading pauses exceeding the interval.","solutions":["Ensure the client keeps sending chunks continuously or restarts the restore on failure","Increase throughput / reduce per-chunk processing time on the client; read the file in a tight loop","Check network stability between client and server; retry the restore after a failure"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// ensure a fast, uninterrupted chunk producer before starting\nif !canReadFileContinuously(restoreFile) {\n\treturn fmt.Errorf(\"restore source must supply chunks without long pauses\")\n}","typeGuard":null,"tryCatchPattern":"err := restoreStream(cfg, r)\nif err != nil && strings.Contains(err.Error(), \"is stalled\") {\n\t// restart restore; resume/checkpoint if supported\n\treturn restoreStream(cfg, reopenReader())\n}","preventionTips":["Feed chunks from a dedicated goroutine that never blocks long","Check network throughput to the server before large restores","Handle client crashes by cleaning up and re-running the restore"],"tags":["jetstream","stream-restore","timeout","nats-server"],"backgroundTag":"restore-stalled","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}