hyperledger/fabric · error
dir %s not empty
Error message
dir %s not empty
What it means
bootstrapFromSnapshottedTxIDs imports a snapshot into a fresh ledger directory, but only if the ledger's block directory is empty (CreateDirIfMissing returns isEmpty). If any files already exist under the ledger's blocks dir, it refuses with 'dir %s not empty' rather than mixing snapshot data with existing blocks.
Source
Thrown at common/ledger/blkstorage/blockfile_mgr.go:185
}
mgr.bcInfo.Store(bcInfo)
return mgr, nil
}
func bootstrapFromSnapshottedTxIDs(
ledgerID string,
snapshotDir string,
snapshotInfo *SnapshotInfo,
conf *Conf,
indexStore *leveldbhelper.DBHandle,
) error {
rootDir := conf.getLedgerBlockDir(ledgerID)
isEmpty, err := fileutil.CreateDirIfMissing(rootDir)
if err != nil {
return err
}
if !isEmpty {
return errors.Errorf("dir %s not empty", rootDir)
}
bsi := &BootstrappingSnapshotInfo{
LastBlockNum: snapshotInfo.LastBlockNum,
LastBlockHash: snapshotInfo.LastBlockHash,
PreviousBlockHash: snapshotInfo.PreviousBlockHash,
}
bsiBytes, err := proto.Marshal(bsi)
if err != nil {
return err
}
if err = fileutil.CreateAndSyncFileAtomically(
rootDir,
bootstrappingSnapshotInfoTempFile,
bootstrappingSnapshotInfoFile,
bsiBytes,View on GitHub (pinned to 2736b63f8f)
Solutions
- Ensure the peer is fresh/reset for that ledger: stop the peer and remove ledgersData/chains/chains/<ledgerID> (or run peer node reset) before importing
- Retry the import — a prior partial import must be cleaned first since it is not resumable
- Verify you are importing on a peer that is not already joined to the channel
- Check ledgerDataPath config points to the intended (empty) data root
Example fix
// before: ImportFromSnapshot fails with 'dir ... not empty' systemctl stop peer rm -rf /var/hyperledger/production/ledgersData/chains/chains/mychannel systemctl start peer # after: import succeeds into empty dir peer node import-snapshot ...
Defensive patterns
Strategy: validation
Validate before calling
// check the target ledger blocks dir is empty before ImportFromSnapshot
func dirIsEmpty(p string) (bool, error) {
if _, err := os.Stat(p); os.IsNotExist(err) { return true, nil }
f, err := os.Open(p)
if err != nil { return false, err }
defer f.Close()
names, err := f.Readdirnames(-1)
if err != nil { return false, err }
return len(names) == 0, nil
} Try / catch
if err := blkstorage.ImportFromSnapshot(...); err != nil {
if strings.Contains(err.Error(), "not empty") {
// recover: wipe the ledger dir (or run 'peer node reset') and retry import
}
return err
} Prevention
- Only import snapshots into a freshly reset peer ('peer node reset' first)
- Never re-run a failed snapshot import without cleaning the ledger directory first
- Confirm the peer is not already joined to the channel before importing
- Point ledgerDataPath at a dedicated, empty data root for snapshot imports
When it happens
Trigger: Calling ImportFromSnapshot (bootstrapFromSnapshottedTxIDs) for a ledgerID whose block directory (ledgersData/chains/chains/<ledgerID>/blocks) already contains files — e.g., the ledger previously existed, or a prior snapshot import partially completed leaving metadata behind.
Common situations: Re-running snapshot import after a failed attempt; importing into a peer that already has the channel/ledger; leftover files from a ledger reset that only cleared some subdirectories; wrong ledgerDataPath pointing at an existing peer's data.
Related errors
- recovery for DB [%s] not possible. Ledger [%s] is created fr
- the supplied snapshots appear to be non-comparable. State db
- error decoding the block number
- error decoding the data hash
- error decoding the previous hash
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/26fb782a99af7d51.
Report an issue: GitHub.