gastownhall/beads · error

proxy.ForceStopUnverified: inspect executable for pid %d: %w

Error message

proxy.ForceStopUnverified: inspect executable for pid %d: %w

What it means

This error wraps a failure while reading the executable basename of the process holding the PID from an unverified (legacy or foreign) PID record during ForceStopUnverified. Before bd will signal any PID it did not verifiably own, it inspects /proc-style process metadata to confirm the binary is actually bd or dolt; if that inspection itself fails (permissions, procfs unavailable, race while the process exits), this error is returned and no signal is sent. It is a safety-gate failure, not a process kill failure.

Source

Thrown at internal/storage/dbproxy/proxy/force_stop.go:208

	if pid <= 0 {
		return fmt.Errorf("proxy.ForceStopUnverified: record %s has invalid pid %d", report.RecordPath, pid)
	}
	// One stable handle covers inspection and signaling, so the PID cannot be
	// recycled between the executable check and the kill on platforms with a
	// pinning primitive (Linux pidfd, Windows process handle).
	proc, gone, err := openUnverifiedProcess(pid)
	if err != nil {
		return fmt.Errorf("proxy.ForceStopUnverified: open pid %d: %w", pid, err)
	}
	if gone {
		report.ProcessWasGone = true
		return nil
	}
	defer proc.close()

	executable, gone, err := proc.executableBasename()
	if err != nil {
		return fmt.Errorf("proxy.ForceStopUnverified: inspect executable for pid %d: %w", pid, err)
	}
	if gone {
		report.ProcessWasGone = true
		return nil
	}
	executable = normalizeForceStopExecutable(executable)
	report.Executable = executable
	if executable != "bd" && executable != "dolt" {
		return fmt.Errorf(
			"proxy.ForceStopUnverified: refusing to signal pid %d from %s: executable basename is %q, want bd or dolt",
			pid,
			report.RecordPath,
			executable,
		)
	}

	// Basename alone would let a recycled PID now running an unrelated bd or
	// dolt be killed; require the command line to tie the process to THIS

View on GitHub (pinned to 71377f2769)

Solutions

  1. Re-run the command; if the PID belonged to an exiting process the retry will report ProcessWasGone and succeed
  2. Check you can read /proc/<pid>/exe (or platform equivalent) for the target PID; if not, stop the process manually
  3. If the record is stale, quarantine it: rename <record> to <record>.stale-<unix-timestamp>, then retry
  4. Run bd as the same user that owns the target process, or inspect inside the container/namespace where it runs

Example fix

// before
report, err := proxy.ForceStopUnverified(ctx, rootDir, pidName, deadline)
if err != nil { log.Fatal(err) }
// after
report, err := proxy.ForceStopUnverified(ctx, rootDir, pidName, deadline)
if err != nil {
    if strings.Contains(err.Error(), "inspect executable") {
        os.Rename(recordPath, recordPath+".stale-"+strconv.FormatInt(time.Now().Unix(), 10))
        report, err = proxy.ForceStopUnverified(ctx, rootDir, pidName, deadline)
    }
    if err != nil { log.Fatal(err) }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check the pid is inspectable before calling
pid := readPidFromRecord(recordPath)
if pid > 0 {
    if _, err := os.Readlink(fmt.Sprintf("/proc/%d/exe", pid)); err != nil {
        // process gone or unreadable: quarantine record first
        os.Rename(recordPath, recordPath+".stale-"+fmt.Sprint(time.Now().Unix()))
    }
}

Type guard

func isInspectExecutableErr(err error) bool {
    return err != nil && strings.Contains(err.Error(), "inspect executable for pid")
}

Try / catch

report, err := proxy.ForceStopUnverified(ctx, rootDir, pidName, deadline)
if isInspectExecutableErr(err) {
    // transient (race) or permission issue: retry once, else quarantine
    os.Rename(recordPath, recordPath+".stale-"+fmt.Sprint(time.Now().Unix()))
    report, err = proxy.ForceStopUnverified(ctx, rootDir, pidName, deadline)
}
if err != nil { return err }

Prevention

When it happens

Trigger: Calling proxy.ForceStopUnverified when the PID from the record cannot be inspected: the process exited between openUnverifiedProcess and executableBasename (race), the procfs entry lacks read permission, the process is a zombie/kernel thread with no exe link, or the platform lacks the required inspection primitive.

Common situations: Stale PID files pointing at processes that just exited; running bd under containers/restricted environments where /proc/<pid>/exe is unreadable or mounted noexec; hardened security modules (SELinux/AppArmor) blocking ptrace-like reads; inspecting system processes owned by another user.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/b00c3089d70cf9bf. Report an issue: GitHub.