hyperledger/fabric · critical

Error creating dir if missing

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.

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.

Appendix: 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)