larksuite/cli · error

busdiscover: mkdir %s: %w

Error message

busdiscover: mkdir %s: %w

What it means

WritePIDFile wraps the failure of vfs.MkdirAll when creating the per-app events directory (mode 0700). The library throws it before taking the alive lock because it cannot guarantee a location to place bus.alive.lock and bus.pid. The wrapped underlying cause (permissions, path issues, filesystem errors) is preserved via %w.

Source

Thrown at internal/event/adapter/localbus/busdiscover/pidfile.go:41

// Handle keeps the lifetime lock fd alive; OS releases on process exit.
type Handle struct {
	lock *lockfile.LockFile
}

// Release is for tests only; production lets process exit release the lock.
func (h *Handle) Release() error {
	if h == nil || h.lock == nil {
		return nil
	}
	return h.lock.Unlock()
}

// WritePIDFile takes the alive lock and atomically writes pid + RFC3339 start time.
// Returns lockfile.ErrHeld if another bus holds the lock.
func WritePIDFile(eventsDir string, pid int) (*Handle, error) {
	if err := vfs.MkdirAll(eventsDir, 0700); err != nil {
		return nil, fmt.Errorf("busdiscover: mkdir %s: %w", eventsDir, err)
	}
	lock := lockfile.New(filepath.Join(eventsDir, aliveLockFileName))
	if err := lock.TryLock(); err != nil {
		return nil, err
	}
	pidPath := filepath.Join(eventsDir, pidFileName)
	tmpPath := pidPath + ".tmp"
	payload := fmt.Sprintf("%d\n%s\n", pid, time.Now().UTC().Format(time.RFC3339))
	if err := vfs.WriteFile(tmpPath, []byte(payload), 0600); err != nil {
		_ = lock.Unlock()
		return nil, fmt.Errorf("busdiscover: write pid tmp: %w", err)
	}
	if err := vfs.Rename(tmpPath, pidPath); err != nil {
		_ = vfs.Remove(tmpPath)
		_ = lock.Unlock()
		return nil, fmt.Errorf("busdiscover: rename pid file: %w", err)
	}
	return &Handle{lock: lock}, nil

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Check the wrapped cause with errors.Is/As to identify the OS error (EACCES, ENOTDIR, ENOSPC) and fix the filesystem condition
  2. Verify the parent of eventsDir exists and is writable by the current user; create or correct the config/state dir path
  3. Remove or rename any regular file that occupies the eventsDir path so a directory can be created
  4. Re-run with a writable alternate state directory (e.g. a fresh LARKSUITE_CLI_CONFIG_DIR) to confirm it is an environment issue

Example fix

// before: writing into a read-only or nonexistent state root
err := busdiscover.WritePIDFile("/var/lib/lark/events", os.Getpid())
// after: ensure the parent state dir exists and is writable first
if err := os.MkdirAll(stateRoot, 0700); err != nil { return err }
err := busdiscover.WritePIDFile(filepath.Join(stateRoot, "events"), os.Getpid())
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the eventsDir parent exists and is writable before calling WritePIDFile
parent := filepath.Dir(eventsDir)
if info, err := os.Stat(parent); err != nil || !info.IsDir() {
    return fmt.Errorf("state dir %s missing", parent)
}
if f, err := os.CreateTemp(parent, ".probe"); err != nil {
    return fmt.Errorf("state dir %s not writable: %w", parent, err)
} else { name := f.Name(); f.Close(); os.Remove(name) }

Try / catch

h, err := busdiscover.WritePIDFile(eventsDir, pid)
if err != nil {
    var perr *fs.PathError
    if errors.As(err, &perr) && (errors.Is(perr.Err, syscall.EACCES) || errors.Is(perr.Err, syscall.ENOSPC)) {
        // fix environment: permissions or disk space, then retry
    }
    return err
}

Prevention

When it happens

Trigger: Calling WritePIDFile(eventsDir, pid) where eventsDir's path cannot be created: parent directory does not exist and cannot be created, a non-directory file exists at a path component, or permission denies creation.

Common situations: LARKSUITE_CLI_CONFIG_DIR or state dir pointing at a read-only mount, a stale regular file occupying the eventsDir path, running under a different user after a sudo-based install, or disk-full/EDQUOT on the state volume.

Understand the failure class

Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/9c4e5c00dc9c5136. Report an issue: GitHub.