gastownhall/beads · error

bd %s: %w: %s

Error message

bd %s: %w: %s

What it means

Produced by runBdPrime's helper when re-invoking the bd binary (`os.Args[0] bd prime ...`) via exec.CommandContext and the subprocess fails. The error bundles the full command line, the exec/exit error, and the trimmed combined stdout+stderr of the child, so %w wraps e.g. 'exit status 1' while the tail shows prime's actual output.

Source

Thrown at cmd/bd/agent_hook.go:29

	"strings"
)

// Shared helpers for the agent lifecycle hook commands (codex-hook, cursor-hook).
// Each agent keeps its own event names, input/output schemas, and test stubs, but
// the prime-runner and one-shot refresh-marker mechanics are identical and live
// here to avoid divergence.

// runBdPrime shells out to `bd prime [args...]` and returns its combined output.
// The hooks exec a subprocess (rather than calling prime in process) to avoid
// re-entrant store initialization.
func runBdPrime(ctx context.Context, args ...string) (string, error) {
	cmdArgs := append([]string{"prime"}, args...)
	// #nosec G702 - os.Args[0] is this bd binary re-invoking itself; cmdArgs is the
	// fixed "prime" subcommand plus internal flags, never attacker-controlled input.
	cmd := exec.CommandContext(ctx, os.Args[0], cmdArgs...)
	out, err := cmd.CombinedOutput()
	if err != nil {
		return "", fmt.Errorf("bd %s: %w: %s", strings.Join(cmdArgs, " "), err, strings.TrimSpace(string(out)))
	}
	return string(out), nil
}

// agentHookMarkerBaseDir returns the cache directory for one-shot
// post-compaction refresh markers for a given agent (subdir e.g. "codex-hooks").
// override redirects the location for tests.
func agentHookMarkerBaseDir(subdir, override string) string {
	if override != "" {
		return override
	}
	if dir, err := os.UserCacheDir(); err == nil && dir != "" {
		return filepath.Join(dir, "beads", subdir)
	}
	return filepath.Join(os.TempDir(), "beads-"+subdir)
}

// agentHookMarkerPath derives a per-session, per-workspace marker file under

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the trailing %s portion — it contains bd prime's own stderr explaining the failure.
  2. Run `bd prime` manually in the same directory to reproduce and see the full output.
  3. Ensure the current working directory has an initialized beads store (bd init) before hooks fire.
  4. If the binary path is stale, reinstall/upgrade bd and retry.
  5. For timeouts, increase the hook's context budget or reduce prime's workload.

Example fix

// before
Error: bd prime: exit status 1: no beads database found

// after
$ cd /repo && bd init && bd prime   # then rerun the hook
Defensive patterns

Strategy: try-catch

Validate before calling

bin, err := os.Executable() // resolve a guaranteed-valid bd binary
if err != nil { return err }
if _, err := os.Stat(bin); err != nil { return fmt.Errorf("bd binary missing: %w", err) }

Type guard

func isPrimeExecError(err error) bool {
	return err != nil && strings.Contains(err.Error(), "bd prime:")
}

Try / catch

out, err := runBdPrime(ctx, args...)
if err != nil {
	var exitErr *exec.ExitError
	if errors.As(err, &exitErr) {
		// %w is the exit error; the message tail holds prime's stderr
		log.Printf("bd prime failed: %v", err)
	}
	if errors.Is(err, context.DeadlineExceeded) {
		log.Printf("bd prime timed out")
	}
}

Prevention

When it happens

Trigger: The re-executed `bd prime` subcommand exits non-zero: prime's internal checks fail, the binary cannot start, or ctx is cancelled before completion; the parent (an agent hook) then surfaces this wrapped error.

Common situations: PATH/cwd where os.Args[0] resolves to a broken or stale binary; hooks running in an environment missing the database so prime errors; context deadline exceeded in long compaction hooks; permissions preventing re-exec of the same binary.

Related errors


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