hyperledger/fabric · critical

Could not seek block file [%s] to startOffset [%d]. New posi

Error message

Could not seek block file [%s] to startOffset [%d]. New position = [%d]

What it means

A panic (not a returned error) raised when file.Seek reports success but the resulting position does not equal the requested startOffset. Since bufio/os seek on a regular file should always land exactly at the requested offset, this signals an inconsistency the code treats as a programming/environment invariant violation. It crashes the calling goroutine, which in Fabric means crashing the process.

Source

Thrown at common/ledger/blkstorage/block_stream.go:67

}

// /////////////////////////////////
// blockfileStream functions
// //////////////////////////////////
func newBlockfileStream(rootDir string, fileNum int, startOffset int64) (*blockfileStream, error) {
	filePath := deriveBlockfilePath(rootDir, fileNum)
	logger.Debugf("newBlockfileStream(): filePath=[%s], startOffset=[%d]", filePath, startOffset)
	var file *os.File
	var err error
	if file, err = os.OpenFile(filePath, os.O_RDONLY, 0o600); err != nil {
		return nil, errors.Wrapf(err, "error opening block file %s", filePath)
	}
	var newPosition int64
	if newPosition, err = file.Seek(startOffset, 0); err != nil {
		return nil, errors.Wrapf(err, "error seeking block file [%s] to startOffset [%d]", filePath, startOffset)
	}
	if newPosition != startOffset {
		panic(fmt.Sprintf("Could not seek block file [%s] to startOffset [%d]. New position = [%d]",
			filePath, startOffset, newPosition))
	}
	s := &blockfileStream{fileNum, file, bufio.NewReader(file), startOffset}
	return s, nil
}

func (s *blockfileStream) nextBlockBytes() ([]byte, error) {
	blockBytes, _, err := s.nextBlockBytesAndPlacementInfo()
	return blockBytes, err
}

// nextBlockBytesAndPlacementInfo returns bytes for the next block
// along with the offset information in the block file.
// An error `ErrUnexpectedEndOfBlockfile` is returned if a partial written data is detected
// which is possible towards the tail of the file if a crash had taken place during appending of a block
func (s *blockfileStream) nextBlockBytesAndPlacementInfo() ([]byte, *blockPlacementInfo, error) {
	var lenBytes []byte
	var err error

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Ensure the ledger path is on a normal local filesystem (ext4/xfs), not a pipe, device, or unusual FUSE mount
  2. Confirm the file at deriveBlockfilePath(rootDir, fileNum) is a regular file (os.Stat mode check)
  3. Recover the process (it panics) and retry after fixing the storage setup

Example fix

// defensive pre-check before constructing the stream
info, err := os.Stat(deriveBlockfilePath(rootDir, fileNum))
if err != nil || !info.Mode().IsRegular() {
    return fmt.Errorf("blockfile %s is not a regular file", path)
}
Defensive patterns

Strategy: validation

Validate before calling

info, err := os.Stat(deriveBlockfilePath(rootDir, fileNum))
if err != nil || !info.Mode().IsRegular() {
    return fmt.Errorf("blockfile %d is not a regular seekable file", fileNum)
}

Type guard

func isRegularFile(path string) bool {
    info, err := os.Stat(path)
    return err == nil && info.Mode().IsRegular()
}

Prevention

When it happens

Trigger: newBlockfileStream where file.Seek(startOffset, 0) returns newPosition != startOffset — practically only when seeking something that is not a regular seekable file (e.g. a special file, or a pipe substituted for the ledger file).

Common situations: Ledger 'file' path pointing at a device/FIFO via misconfiguration or bind-mount; exotic FUSE/overlay filesystems reporting wrong positions; tampering or intercepting file I/O (e.g. some security agents).

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/9ab155060373fa2d. Report an issue: GitHub.