hyperledger/fabric · critical

Error creating dir if missing: %s

Error message

Error creating dir if missing: %s

What it means

FileLock.Lock panics (does not return the error) when fileutil.CreateDirIfMissing fails for the lock's directory path. The message carries the wrapped cause. This is a programmer/infrastructure failure — the lock directory could not be created or inspected — so the code deliberately crashes rather than proceeding without a lock.

Source

Thrown at common/ledger/util/leveldbhelper/leveldb_helper.go:211

	return &FileLock{
		filePath: filePath,
	}
}

// Lock acquire a file lock. We achieve this by opening
// a db for the given filePath. Internally, leveldb acquires a
// file lock while opening a db. If the db is opened again by the same or
// another process, error would be returned. When the db is closed
// or the owner process dies, the lock would be released and hence
// the other process can open the db. We exploit this leveldb
// functionality to acquire and release file lock as the leveldb
// supports this for Windows, Solaris, and Unix.
func (f *FileLock) Lock() error {
	dbOpts := &opt.Options{}
	var err error
	var dirEmpty bool
	if dirEmpty, err = fileutil.CreateDirIfMissing(f.filePath); err != nil {
		panic(fmt.Sprintf("Error creating dir if missing: %s", err))
	}
	dbOpts.ErrorIfMissing = !dirEmpty
	db, err := leveldb.OpenFile(f.filePath, dbOpts)
	if err != nil && err == syscall.EAGAIN {
		return errors.Errorf("lock is already acquired on file %s", f.filePath)
	}
	if err != nil {
		panic(fmt.Sprintf("Error acquiring lock on file %s: %s", f.filePath, err))
	}

	// only mutate the lock db reference AFTER validating that the lock was held.
	f.db = db

	return nil
}

// Determine if the lock is currently held open.
func (f *FileLock) IsLocked() bool {

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Create the lock directory manually and grant the process user write permission on it.
  2. Fix the configured file lock path in configuration to a writable location.
  3. Check that the filesystem is not mounted read-only.
  4. Since this panics, recover at a process boundary and log f.filePath plus the cause for diagnosis.

Example fix

// before
err := fileLock.Lock()
// after
func safeLock(fl *leveldbhelper.FileLock) (err error) {
  defer func() { if r := recover(); r != nil { err = fmt.Errorf("file lock panic: %v", r) } }()
  return fl.Lock()
}
Defensive patterns

Strategy: validation

Validate before calling

if err := os.MkdirAll(lockDir, 0o755); err != nil {
  return fmt.Errorf("cannot prepare lock dir %s: %w", lockDir, err)
}
if !writable(lockDir) { return fmt.Errorf("lock dir %s not writable", lockDir) }

Type guard

func recoveredLockPanic(r interface{}) error {
  if r == nil { return nil }
  if s, ok := r.(string); ok && strings.HasPrefix(s, "Error creating dir") {
    return errors.New(s)
  }
  return fmt.Errorf("unexpected panic: %v", r)
}

Try / catch

func lockSafely(fl *leveldbhelper.FileLock) (err error) {
  defer func() { if r := recover(); r != nil { err = fmt.Errorf("file lock failed: %v", r) } }()
  return fl.Lock()
}

Prevention

When it happens

Trigger: Lock directory does not exist and cannot be created (permissions, read-only filesystem, invalid path); an I/O error occurs while stat-ing/creating the directory. Reached via TestFileLock-style usage of FileLock.

Common situations: Running the process as a user without write access to the lock directory; incorrect configured path; container with read-only rootfs; NFS mounts lacking directory-create support.

Related errors


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