{"record":{"id":"7173bcf1bffc8873","repo":"nats-io/nats-server","slug":"failed-to-truncate-msg-block-d-file-not-open","errorCode":null,"errorMessage":"failed to truncate msg block %d, file not open","messagePattern":"failed to truncate msg block (.+?), file not open","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/filestore.go","lineNumber":6907,"sourceCode":"\t\t// and would otherwise have compressed data and allow to write uncompressed data in the same block.\n\t\tif err = mb.atomicOverwriteFile(buf, false); err != nil {\n\t\t\treturn 0, 0, err\n\t\t}\n\t} else if mb.mfd != nil {\n\t\tif err = mb.mfd.Truncate(eof); err != nil {\n\t\t\treturn 0, 0, err\n\t\t}\n\t\tif err = mb.mfd.Sync(); err != nil {\n\t\t\treturn 0, 0, err\n\t\t}\n\t\t// Update our checksum.\n\t\tvar lchk [8]byte\n\t\tif _, err = mb.mfd.ReadAt(lchk[:], eof-8); err != nil {\n\t\t\treturn 0, 0, err\n\t\t}\n\t\tcopy(mb.lchk[0:], lchk[:])\n\t} else {\n\t\treturn 0, 0, fmt.Errorf(\"failed to truncate msg block %d, file not open\", mb.index)\n\t}\n\n\t// Update our last msg.\n\tatomic.StoreUint64(&mb.last.seq, tseq)\n\tmb.last.ts = ts\n\n\t// Clear our cache.\n\tmb.clearCacheAndOffset()\n\n\t// Redo per subject info for this block.\n\tif err = mb.resetPerSubjectInfo(); err != nil {\n\t\treturn purged, bytes, err\n\t}\n\n\t// Load msgs again.\n\treturn purged, bytes, mb.loadMsgsWithLock()\n}\n","sourceCodeStart":6889,"sourceCodeEnd":6925,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/filestore.go#L6889-L6925","documentation":"Returned by FileStore msg block truncation when the block's message file descriptor (mb.mfd) is not open. Truncation requires reading a trailing 8-byte length check value with ReadAt, which is impossible on a closed/nil file handle. The library guards against operating on blocks whose backing file has been closed or never opened.","triggerScenarios":"Calling truncateMsgBlock (via stream purge/truncate APIs) on a message block whose mfd is nil — e.g. after the block was closed during recovery, or truncation attempted while the block file is not open because the block was compacted/closed earlier.","commonSituations":"Operating on a recovered stream where a block was closed during a prior failure; concurrent close of a stream while a truncate is in flight; calling internal-style purge APIs on blocks outside the expected open lifecycle.","solutions":["Ensure the stream/block is open (call ensureMsgBlockOpened or openMsgBlock) before truncating","Check for concurrent stream close/delete racing the truncate; serialize operations on the stream","If this appears during recovery, inspect disk state for corrupt block metadata and restart the server to re-open blocks","Update to a recent NATS server version; block lifecycle around truncation has had fixes"],"exampleFix":"// before: truncating a block that was closed\nblk.truncate()\n\n// after: ensure file is open first\nif err := fs.ensureMsgBlockOpened(blk); err != nil { return err }\nblk.truncate()","handlingStrategy":"try-catch","validationCode":"// Go: ensure the stream is healthy before truncating\ninfo, err := js.StreamInfo(ctx, \"ORDERS\")\nif err != nil || info.State.Msgs == 0 {\n    return fmt.Errorf(\"stream unavailable, skip truncate: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"err := stream.Purge(ctx, nats.PurgeSequence(seq))\nvar serr *nats.APIError\nif errors.As(err, &serr) && strings.Contains(serr.Description, \"file not open\") {\n    // restart server / reopen stream, then retry once\n}","preventionTips":["Don't purge/truncate streams concurrently with stream delete/close","Restart the server cleanly if recovery left blocks closed","Upgrade nats-server to pick up block lifecycle fixes","Monitor stream health with `nats stream info` before maintenance operations"],"tags":["jetstream","filestore","stream-truncate","file-handle"],"backgroundTag":"file-not-open","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}