larksuite/cli · error
busdiscover: write pid tmp: %w
Error message
busdiscover: write pid tmp: %w
What it means
WritePIDFile wraps the failure of vfs.WriteFile when writing the temporary pid file (bus.pid.tmp, mode 0600) inside the already-created eventsDir. On failure it releases the alive lock before returning so the lock is not leaked. The underlying OS error is preserved via %w.
Source
Thrown at internal/event/adapter/localbus/busdiscover/pidfile.go:52
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
}
func readPIDFile(eventsDir string) (int, time.Time, error) {
pidPath := filepath.Join(eventsDir, pidFileName)
data, err := vfs.ReadFile(pidPath)
if err != nil {
return 0, time.Time{}, err
}
lines := strings.SplitN(strings.TrimSpace(string(data)), "\n", 2)
if len(lines) < 2 {
return 0, time.Time{}, fmt.Errorf("busdiscover: malformed pid file %s", pidPath)View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Inspect the wrapped cause: ENOSPC/EDQUOT means free disk space or raise quota on the state volume
- Check the eventsDir still exists and is writable (ls -ld); recreate it if a cleaner removed it
- Retry WritePIDFile after transient conditions; the lock is released so reacquisition is safe
- Look for external cleanup jobs or security policies interfering with the config/state directory
Example fix
// before: writing to a volume that is full
err := busdiscover.WritePIDFile(eventsDir, pid) // fails: busdiscover: write pid tmp: ... no space left
// after: preflight the volume before starting the bus
if stat, err := os.Statvfs(eventsDir); err != nil || stat.Bavail == 0 { return fmt.Errorf("state volume full") }
err := busdiscover.WritePIDFile(eventsDir, pid) Defensive patterns
Strategy: retry
Validate before calling
// Preflight: confirm eventsDir exists and accepts writes before WritePIDFile
if info, err := os.Stat(eventsDir); err != nil || !info.IsDir() {
return fmt.Errorf("events dir %s missing", eventsDir)
}
probe := filepath.Join(eventsDir, ".write-probe")
if err := os.WriteFile(probe, []byte("ok"), 0600); err != nil {
return fmt.Errorf("events dir %s not writable: %w", eventsDir, err)
}
os.Remove(probe) Try / catch
var h *busdiscover.Handle
var err error
for i := 0; i < 3; i++ {
h, err = busdiscover.WritePIDFile(eventsDir, pid)
if err == nil || !errors.As(err, new(*fs.PathError)) {
break
}
time.Sleep(200 * time.Millisecond) // transient ENOSPC/cleaner race
} Prevention
- Keep free space headroom on the state volume; alert on ENOSPC/EDQUOT
- Exclude the CLI state directory from aggressive cleanup jobs (tmpwatch, disk cleaners)
- Avoid read-only remounts or SELinux/AppArmor denials on the state path
- Release/reacquire is safe on this failure — the lock is unlocked before the error returns
When it happens
Trigger: Calling WritePIDFile after the eventsDir was created and the lock acquired, but the tmp write fails: disk full, quota exceeded, permission loss on the directory, or the directory removed concurrently by another process.
Common situations: Disk full on the state partition (ENOSPC), another process or cleaner deleting the events dir between mkdir and write, SELinux/AppArmor denying writes, or a read-only remount of the state volume.
Related errors
- busdiscover: mkdir %s: %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/f4e93d49624a0d36.
Report an issue: GitHub.