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

  1. 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
  2. Retry the import — a prior partial import must be cleaned first since it is not resumable
  3. Verify you are importing on a peer that is not already joined to the channel
  4. 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

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


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