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}, nilView on GitHub (pinned to 7fd6ef3c07)
Solutions
- Check the wrapped cause with errors.Is/As to identify the OS error (EACCES, ENOTDIR, ENOSPC) and fix the filesystem condition
- Verify the parent of eventsDir exists and is writable by the current user; create or correct the config/state dir path
- Remove or rename any regular file that occupies the eventsDir path so a directory can be created
- 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
- Provision the CLI state/config directory with correct ownership before launching the bus
- Do not point the state dir at read-only mounts, network shares, or tmpfs cleared on reboot
- Avoid creating regular files where the eventsDir directory should live
- Monitor disk space and quota on the volume hosting the state directory
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
- busdiscover: write pid tmp: %w
- busdiscover: rename pid file: %w
- busdiscover: malformed pid file %s
- busdiscover: malformed pid in %s: %w
- busdiscover: malformed timestamp in %s: %w
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/9c4e5c00dc9c5136.
Report an issue: GitHub.