{"record":{"id":"c9e7be410c1cc9ea","repo":"hyperledger/fabric","slug":"error-getting-block-file-stat","errorCode":null,"errorMessage":"error getting block file stat","messagePattern":"error getting block file stat","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/ledger/blkstorage/block_stream.go","lineNumber":90,"sourceCode":"}\n\nfunc (s *blockfileStream) nextBlockBytes() ([]byte, error) {\n\tblockBytes, _, err := s.nextBlockBytesAndPlacementInfo()\n\treturn blockBytes, err\n}\n\n// nextBlockBytesAndPlacementInfo returns bytes for the next block\n// along with the offset information in the block file.\n// An error `ErrUnexpectedEndOfBlockfile` is returned if a partial written data is detected\n// which is possible towards the tail of the file if a crash had taken place during appending of a block\nfunc (s *blockfileStream) nextBlockBytesAndPlacementInfo() ([]byte, *blockPlacementInfo, error) {\n\tvar lenBytes []byte\n\tvar err error\n\tvar fileInfo os.FileInfo\n\tmoreContentAvailable := true\n\n\tif fileInfo, err = s.file.Stat(); err != nil {\n\t\treturn nil, nil, errors.Wrapf(err, \"error getting block file stat\")\n\t}\n\tif s.currentOffset == fileInfo.Size() {\n\t\tlogger.Debugf(\"Finished reading file number [%d]\", s.fileNum)\n\t\treturn nil, nil, nil\n\t}\n\tremainingBytes := fileInfo.Size() - s.currentOffset\n\t// Peek 8 or smaller number of bytes (if remaining bytes are less than 8)\n\t// Assumption is that a block size would be small enough to be represented in 8 bytes varint\n\tpeekBytes := 8\n\tif remainingBytes < int64(peekBytes) {\n\t\tpeekBytes = int(remainingBytes)\n\t\tmoreContentAvailable = false\n\t}\n\tlogger.Debugf(\"Remaining bytes=[%d], Going to peek [%d] bytes\", remainingBytes, peekBytes)\n\tif lenBytes, err = s.reader.Peek(peekBytes); err != nil {\n\t\treturn nil, nil, errors.Wrapf(err, \"error peeking [%d] bytes from block file\", peekBytes)\n\t}\n\tlength, n := protowire.ConsumeVarint(lenBytes)","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/common/ledger/blkstorage/block_stream.go#L72-L108","documentation":"Wraps the os.File.Stat error when nextBlockBytesAndPlacementInfo cannot determine the current size of the blockfile. File size is required to decide whether more content remains or the stream has hit end-of-file. Without a successful Stat the stream cannot safely continue reading.","triggerScenarios":"nextBlockBytesAndPlacementInfo (via nextBlockBytes) calls s.file.Stat() and it fails — file descriptor closed, file deleted mid-stream, or I/O error.","commonSituations":"Ledger file removed/rotated underneath an open stream (cleanup job or manual rm); descriptor closed twice by a bug; storage errors on a failing disk or detached network volume.","solutions":["Check the wrapped OS error; ENOENT means the blockfile was deleted while being read","Stop any external cleanup/rotation of ledger files while the peer is running","Reopen the block stream (fresh newBlockfileStream) after restoring the file","Check storage health if EIO is reported"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"var bs *blockStream\nvar err error\nfor attempt := 0; attempt < 3; attempt++ {\n    bs, err = newBlockStream(rootDir, num, offset)\n    if err == nil { break }\n    if errors.Is(errors.Cause(err), os.ErrNotExist) { return restoreFile() }\n    time.Sleep(backoff(attempt))\n}","preventionTips":["Never delete or rotate blockfiles while the peer is live","Exclude the ledger directory from aggressive cleanup cron jobs","Monitor storage health to catch EIO early"],"tags":["fabric","ledger","filesystem","stat"],"backgroundTag":"file-stat-failed","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}