charmbracelet/crush · error
failed to start crush server
Error message
failed to start crush server: %v
What it means
Wraps the error returned by exec.Cmd.Start() when launching a detached Crush server child process. It means the OS refused to spawn the configured binary - typically the executable path does not exist, is not executable, or the working directory is invalid. The wrap preserves the underlying errno (e.g. 'no such file or directory').
Solutions
- Verify the crush binary exists and is executable: `which crush && test -x $(which crush)`
- Check that PATH in the spawning environment includes the binary's directory
- Run the command manually to see the underlying errno from the wrapped message
- Reinstall or update crush if the binary was removed by an upgrade
Example fix
// before: binary resolved from an env-var-derived path that may be empty
exe := os.Getenv("CRUSH_BIN")
c := exec.Command(exe, "serve")
// after: resolve explicitly and fail early
exe, err := exec.LookPath("crush")
if err != nil {
return fmt.Errorf("crush binary not found in PATH: %w", err)
}
c := exec.Command(exe, "serve") Defensive patterns
Strategy: validation
Validate before calling
exe, err := exec.LookPath("crush")
if err != nil {
return fmt.Errorf("crush binary not found: %w", err)
}
if info, err := os.Stat(exe); err != nil || info.IsDir() || info.Mode()&0o111 == 0 {
return fmt.Errorf("crush binary missing or not executable: %s", exe)
} Try / catch
if err := startDetachedServer(cmd); err != nil {
var execErr *exec.Error
if errors.As(err, &execErr) {
slog.Error("Server binary not found; check PATH/install", "bin", execErr.Name)
}
return err
} Prevention
- Resolve the binary with exec.LookPath instead of hand-built paths
- Keep PATH intact in service/CI environments (absolute path fallback)
- Verify the executable bit after installs and upgrades
- Check the spawn environment's PATH before spawning
When it happens
Trigger: Calling spawnAndWaitReady -> startDetachedServer where exec.Command points at a non-existent or non-executable binary, the command's Dir is missing, or resource limits (fork failures) prevent process creation.
Common situations: Crush installed outside PATH; PATH stripped in systemd/launchd/cron environments; stale binary after an upgrade or uninstall; minimal containers without the binary.
Related errors
- error starting shell
- failed to detach crush server process
- agent configuration is missing
- agent configuration not found
- agent coordinator not initialized
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/1b8e94b69247defe.
Report an issue: GitHub.
Appendix: source
Thrown at internal/cmd/root.go:895
stderrPath := filepath.Join(chDir, "stderr.log")
detachProcess(c)
stdout, err := os.Create(stdoutPath)
if err != nil {
return fmt.Errorf("failed to create stdout log file: %v", err)
}
defer stdout.Close()
c.Stdout = stdout
stderr, err := os.Create(stderrPath)
if err != nil {
return fmt.Errorf("failed to create stderr log file: %v", err)
}
defer stderr.Close()
c.Stderr = stderr
if err := c.Start(); err != nil {
return fmt.Errorf("failed to start crush server: %v", err)
}
if err := c.Process.Release(); err != nil {
return fmt.Errorf("failed to detach crush server process: %v", err)
}
return nil
}
func shouldEnableMetrics(cfg *config.Config) bool {
if v, _ := strconv.ParseBool(os.Getenv("CRUSH_DISABLE_METRICS")); v {
return false
}
if v, _ := strconv.ParseBool(os.Getenv("DO_NOT_TRACK")); v {
return false
}
if cfg.Options.DisableMetrics {
return falseView on GitHub (pinned to 7944b8e522)