{"record":{"id":"1b8e94b69247defe","repo":"charmbracelet/crush","slug":"failed-to-start-crush-server-v","errorCode":null,"errorMessage":"failed to start crush server: %v","messagePattern":"failed to start crush server: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/cmd/root.go","lineNumber":895,"sourceCode":"\tstderrPath := filepath.Join(chDir, \"stderr.log\")\n\tdetachProcess(c)\n\n\tstdout, err := os.Create(stdoutPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create stdout log file: %v\", err)\n\t}\n\tdefer stdout.Close()\n\tc.Stdout = stdout\n\n\tstderr, err := os.Create(stderrPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create stderr log file: %v\", err)\n\t}\n\tdefer stderr.Close()\n\tc.Stderr = stderr\n\n\tif err := c.Start(); err != nil {\n\t\treturn fmt.Errorf(\"failed to start crush server: %v\", err)\n\t}\n\n\tif err := c.Process.Release(); err != nil {\n\t\treturn fmt.Errorf(\"failed to detach crush server process: %v\", err)\n\t}\n\n\treturn nil\n}\n\nfunc shouldEnableMetrics(cfg *config.Config) bool {\n\tif v, _ := strconv.ParseBool(os.Getenv(\"CRUSH_DISABLE_METRICS\")); v {\n\t\treturn false\n\t}\n\tif v, _ := strconv.ParseBool(os.Getenv(\"DO_NOT_TRACK\")); v {\n\t\treturn false\n\t}\n\tif cfg.Options.DisableMetrics {\n\t\treturn false","sourceCodeStart":877,"sourceCodeEnd":913,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/cmd/root.go#L877-L913","documentation":"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').","triggerScenarios":"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.","commonSituations":"Crush installed outside PATH; PATH stripped in systemd/launchd/cron environments; stale binary after an upgrade or uninstall; minimal containers without the binary.","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"],"exampleFix":"// before: binary resolved from an env-var-derived path that may be empty\nexe := os.Getenv(\"CRUSH_BIN\")\nc := exec.Command(exe, \"serve\")\n// after: resolve explicitly and fail early\nexe, err := exec.LookPath(\"crush\")\nif err != nil {\n\treturn fmt.Errorf(\"crush binary not found in PATH: %w\", err)\n}\nc := exec.Command(exe, \"serve\")","handlingStrategy":"validation","validationCode":"exe, err := exec.LookPath(\"crush\")\nif err != nil {\n\treturn fmt.Errorf(\"crush binary not found: %w\", err)\n}\nif info, err := os.Stat(exe); err != nil || info.IsDir() || info.Mode()&0o111 == 0 {\n\treturn fmt.Errorf(\"crush binary missing or not executable: %s\", exe)\n}","typeGuard":null,"tryCatchPattern":"if err := startDetachedServer(cmd); err != nil {\n\tvar execErr *exec.Error\n\tif errors.As(err, &execErr) {\n\t\tslog.Error(\"Server binary not found; check PATH/install\", \"bin\", execErr.Name)\n\t}\n\treturn err\n}","preventionTips":["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"],"tags":["process-spawn","exec","go"],"backgroundTag":"exec-command-not-found","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}