{"record":{"id":"d08e96db985c2749","repo":"charmbracelet/crush","slug":"could-not-run-command-w-d08e96","errorCode":null,"errorMessage":"could not run command: %w","messagePattern":"could not run command: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/shell/shell.go","lineNumber":278,"sourceCode":"\tvar runner *interp.Runner\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\terr = fmt.Errorf(\"command execution panic: %v\", r)\n\t\t}\n\t\tif runner != nil {\n\t\t\ts.updateShellFromRunner(runner)\n\t\t}\n\t\ts.logger.InfoPersist(\"command finished\", \"command\", command, \"err\", err)\n\t}()\n\n\tline, err := syntax.NewParser().Parse(strings.NewReader(command), \"\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"could not parse command: %w\", err)\n\t}\n\n\trunner, err = s.newInterp(nil, stdout, stderr)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"could not run command: %w\", err)\n\t}\n\n\terr = runner.Run(ctx, line)\n\treturn err\n}\n\n// exec executes commands using a cross-platform shell interpreter.\nfunc (s *Shell) exec(ctx context.Context, command string) (string, string, error) {\n\tvar stdout, stderr bytes.Buffer\n\terr := s.execCommon(ctx, command, &stdout, &stderr)\n\treturn stdout.String(), stderr.String(), err\n}\n\n// execStream executes commands using POSIX shell emulation with streaming output\nfunc (s *Shell) execStream(ctx context.Context, command string, stdout, stderr io.Writer) error {\n\treturn s.execCommon(ctx, command, stdout, stderr)\n}\n","sourceCodeStart":260,"sourceCodeEnd":296,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/shell/shell.go#L260-L296","documentation":"In execCommon, after successful parsing the shell builds an interpreter with s.newInterp(nil, stdout, stderr). If construction fails, the error is wrapped as \"could not run command: %w\" and no command runs. This reflects an environment/configuration problem (working directory, env, streams) rather than shell syntax.","triggerScenarios":"Calling Shell.exec/execStream while the shell's cwd (set via SetWorkingDir) no longer exists, the configured environment is invalid, or stream writers supplied to the Shell are unsuitable, causing newInterp to fail.","commonSituations":"Long-running sessions where the original working directory was deleted between commands; CI containers removing temp dirs; misconfigured env plumbing through the Shell.","solutions":["Check os.Stat on the shell's current working directory and SetWorkingDir to a valid directory if missing.","Inspect the wrapped %w error for the concrete cause from newInterp.","Ensure stdout/stderr writers passed to the Shell are non-nil and usable.","Recreate the Shell instance if its environment state has become invalid."],"exampleFix":"// before\nsh.Exec(ctx, cmd) // fails after cwd deleted\n// after\nif _, err := os.Stat(sh.WorkingDir()); err != nil {\n\tsh.SetWorkingDir(\"/tmp\")\n}\nsh.Exec(ctx, cmd)","handlingStrategy":"validation","validationCode":"if _, err := os.Stat(sh.WorkingDir()); err != nil {\n\t_ = sh.SetWorkingDir(\"/tmp\") // or recreate\n}","typeGuard":null,"tryCatchPattern":"err := sh.Exec(ctx, cmd)\nif err != nil && strings.HasPrefix(err.Error(), \"could not run command\") {\n\t// verify/repair cwd+env, then retry once\n}","preventionTips":["Periodically verify the shell's cwd still exists in long-running sessions.","Point the shell at stable directories, not ephemeral temp dirs that get cleaned.","Ensure stream writers passed to the Shell remain valid for its lifetime.","Recreate the Shell if configuration state becomes invalid."],"tags":["shell","runner-setup","environment"],"backgroundTag":"shell-execution-setup-failed","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}