gastownhall/beads · error

capture spawning process identity: %w

Error message

capture spawning process identity: %w

What it means

Returned by forkExecChild when procid.Capture(os.Getpid()) fails while recording the spawning process's identity (PID plus birth fingerprint) for the spawn marker. The marker lets later sessions verify whether the recorded spawner is still alive, so a failed capture aborts the spawn.

Source

Thrown at internal/storage/dbproxy/proxy/endpoint.go:493

			args = append(args, "--external-keep-alive", ext.KeepAlivePeriod.String())
		}
	}

	logFile, err := os.OpenFile(opts.LogFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o600) //nolint:gosec // G304: logFilePath is caller-derived (workspace path), not user-request input
	if err != nil {
		return nil, fmt.Errorf("open log file %q: %w", opts.LogFilePath, err)
	}

	cmd := exec.Command(self, args...)
	cmd.Stdin = nil
	cmd.Stdout = logFile
	cmd.Stderr = logFile
	cmd.SysProcAttr = procAttrDetached()

	birth, err := procid.Capture(os.Getpid())
	if err != nil {
		_ = logFile.Close()
		return nil, fmt.Errorf("capture spawning process identity: %w", err)
	}
	marker := spawnMarker{
		Schema:      1,
		PID:         os.Getpid(),
		Birth:       string(birth),
		StopEpoch:   stopEpoch,
		StartedUnix: time.Now().Unix(),
	}
	if err := writeSpawnMarker(rootDir, marker); err != nil {
		_ = logFile.Close()
		return nil, err
	}

	// The marker is durable before proxy.lock is released. Shutdown treats a
	// matching live owner as an in-progress start and waits; the child removes
	// it only after acquiring proxy.lock. This closes the release-before-Start
	// window without making the child deadlock on the parent's flock.
	released = true

View on GitHub (pinned to 71377f2769)

Solutions

  1. Ensure /proc is mounted and readable for the current process inside the container/sandbox.
  2. Relax seccomp/AppArmor rules that deny reading /proc/self stat data for bd.
  3. Run bd outside the restricted environment (host namespace or less hardened container) and retry.
  4. Check the wrapped procid error to identify the exact sysctl/proc entry that failed.

Example fix

// before: container masks /proc so identity capture fails
docker run --security-opt seccomp=restrictive image bd doctor
// after: allow procfs reads / run with proc mounted
docker run -v /proc:/proc:ro --security-opt seccomp=unconfined image bd doctor
Defensive patterns

Strategy: validation

Validate before calling

// Probe that procfs identity data is readable before spawning
if b, err := os.ReadFile("/proc/self/stat"); err != nil || len(b) == 0 {
    return fmt.Errorf("procfs unreadable; procid.Capture will fail: %w", err)
}

Try / catch

ep, err := GetCreateDatabaseProxyServerEndpoint(rootDir, opts)
if err != nil && strings.Contains(err.Error(), "capture spawning process identity") {
    return fmt.Errorf("environment blocks /proc inspection; run outside the hardened sandbox: %w", err)
}

Prevention

When it happens

Trigger: forkExecChild (during GetCreateDatabaseProxyServerEndpoint) when procid.Capture cannot read the current process's birth information — e.g. /proc not mounted or unreadable, restricted procfs in a hardened container, or an unexpected OS-level process-inspection failure.

Common situations: Containers with masked or missing /proc entries; hardened sandboxes (seccomp/AppArmor) blocking /proc self inspection; very unusual environments (some CI runners, chroots without procfs).

Related errors


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