hyperledger/fabric · error

error reading dir %s

Error message

error reading dir %s

What it means

Wraps the os.ReadDir error when retrieveLastFileSuffix cannot list the block storage root directory. This function scans for the highest-numbered blockfile_<n> to build blockfilesInfo; without a directory listing the ledger cannot determine its file layout. Returned by constructBlockfilesInfo, resetToGenesisBlk, and rollback paths.

Source

Thrown at common/ledger/blkstorage/blockfile_helper.go:139

	}
	defer s.close()
	bb, err := s.nextBlockBytes()
	if err != nil {
		return 0, err
	}
	blockInfo, err := extractSerializedBlockInfo(bb)
	if err != nil {
		return 0, err
	}
	return blockInfo.blockHeader.Number, nil
}

func retrieveLastFileSuffix(rootDir string) (int, error) {
	logger.Debugf("retrieveLastFileSuffix()")
	biggestFileNum := -1
	filesInfo, err := os.ReadDir(rootDir)
	if err != nil {
		return -1, errors.Wrapf(err, "error reading dir %s", rootDir)
	}
	for _, fileInfo := range filesInfo {
		name := fileInfo.Name()
		if fileInfo.IsDir() || !isBlockFileName(name) {
			logger.Debugf("Skipping File name = %s", name)
			continue
		}
		fileSuffix := strings.TrimPrefix(name, blockfilePrefix)
		fileNum, err := strconv.Atoi(fileSuffix)
		if err != nil {
			return -1, err
		}
		if fileNum > biggestFileNum {
			biggestFileNum = fileNum
		}
	}
	logger.Debugf("retrieveLastFileSuffix() - biggestFileNum = %d", biggestFileNum)
	return biggestFileNum, err

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Verify the ledger root directory exists and is readable by the peer process (check ledgersData/chains/<chainID>)
  2. Fix permissions/ownership on the ledger directory (match the peer's runtime user)
  3. Correct peer.fileSystemPath or mount the expected volume
  4. If the directory was deleted, restore from backup or re-create the chain (re-join/re-sync)

Example fix

// before
filesInfo, err := os.ReadDir(rootDir)
if err != nil { return -1, err }
// after: validate up front
if info, err := os.Stat(rootDir); err != nil || !info.IsDir() {
    return -1, fmt.Errorf("ledger dir %s missing or not a directory", rootDir)
}
filesInfo, err := os.ReadDir(rootDir)
if err != nil { return -1, errors.Wrapf(err, "error reading dir %s", rootDir) }
Defensive patterns

Strategy: validation

Validate before calling

info, err := os.Stat(rootDir)
if err != nil {
    return fmt.Errorf("ledger root %s missing: %w", rootDir, err)
}
if !info.IsDir() {
    return fmt.Errorf("%s is not a directory", rootDir)
}
if f, err := os.Open(rootDir); err != nil {
    return fmt.Errorf("ledger root %s not readable: %w", rootDir, err)
} else {
    f.Close()
}

Try / catch

suffix, err := retrieveLastFileSuffix(rootDir)
if err != nil {
    if os.IsNotExist(errors.Cause(err)) {
        return initializeEmptyLedgerDir(rootDir)
    }
    return err
}

Prevention

When it happens

Trigger: retrieveLastFileSuffix(rootDir) calls os.ReadDir(rootDir); failure means the rootDir does not exist, is not readable (permissions), or an I/O error occurs.

Common situations: peer.fileSystemPath misconfigured (wrong mount, volume not attached); ledger directory deleted while the peer runs; permission problems after running the peer as different users (root-created files unreadable by the peer user); read-only mounted volume.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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