charmbracelet/crush · error
shell.Run: Cwd is required
Error message
shell.Run: Cwd is required
What it means
shell.Run requires a non-empty RunOptions.Cwd and refuses to silently fall back to the process working directory, because hooks and the bash tool have different notions of a default. Calling Run with the zero-value options (or any options without Cwd) returns this sentinel error before any parsing or execution.
Source
Thrown at internal/shell/run.go:69
// Run parses and executes a shell command using the same mvdan.cc/sh
// interpreter stack that the stateful [Shell] type uses (builtins,
// optional block list, optional Go coreutils). It is safe to call
// concurrently from multiple goroutines: each call builds its own
// [interp.Runner] and shares no state with other callers or with any
// [Shell] instance.
//
// Errors returned from the command itself (non-zero exit, context
// cancellation, parse failures) follow the same conventions as
// [Shell.Exec]: inspect with [IsInterrupt] and [ExitCode].
func Run(ctx context.Context, opts RunOptions) (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("command execution panic: %v", r)
}
}()
if opts.Cwd == "" {
return fmt.Errorf("shell.Run: Cwd is required")
}
stdout := opts.Stdout
if stdout == nil {
stdout = io.Discard
}
stderr := opts.Stderr
if stderr == nil {
stderr = io.Discard
}
line, err := syntax.NewParser().Parse(strings.NewReader(opts.Command), "")
if err != nil {
return fmt.Errorf("could not parse command: %w", err)
}
runner, err := newRunner(opts.Cwd, opts.Env, opts.Stdin, stdout, stderr, opts.BlockFuncs)
if err != nil {View on GitHub (pinned to 7944b8e522)
Solutions
- Always set Cwd in RunOptions, e.g. to an explicit directory or os.Getwd() result owned by the caller.
- For temporary work, pass t.TempDir() (tests) or a dedicated scratch directory.
- If a default is genuinely desired, resolve it at the call site rather than relying on Run.
- Add a constructor or validation helper that fills Cwd so zero-value options cannot reach Run.
Example fix
// before
shell.Run(ctx, shell.RunOptions{Command: "ls"})
// after
cwd, _ := os.Getwd()
shell.Run(ctx, shell.RunOptions{Command: "ls", Cwd: cwd}) Defensive patterns
Strategy: validation
Validate before calling
if opts.Cwd == "" {
return fmt.Errorf("Cwd must be set before calling shell.Run")
} Try / catch
if err != nil {
if err.Error() == "shell.Run: Cwd is required" {
// programmer error: fill Cwd and retry once
}
} Prevention
- Always set Cwd explicitly in RunOptions; never rely on zero values.
- Use t.TempDir() in tests and explicit project dirs in production.
- Add a helper that constructs RunOptions with a required cwd argument.
- Fail fast in callers when cwd resolution fails instead of passing an empty string.
When it happens
Trigger: Calling shell.Run(ctx, shell.RunOptions{}) or constructing RunOptions with Command set but Cwd left as "" — the exact path exercised by the register-builtin and command-blocking tests.
Common situations: Using Go's zero-value struct literal for quick scripts; building options dynamically where the cwd field is set conditionally and skipped; refactors that moved the cwd out of a shared options struct.
Related errors
- empty command
- could not parse command: %w
- prompt is required
- session id missing from context
- agent message id missing from context
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/7a909950870f0c48.
Report an issue: GitHub.