charmbracelet/crush · error
could not parse command: %w
Error message
could not parse command: %w
What it means
Run() in internal/shell/run.go parses the supplied command string with mvdan/sh's syntax.NewParser().Parse before execution. If the shell source cannot be tokenized/parsed (unbalanced quotes, unclosed constructs, invalid syntax), the parse error is wrapped with "could not parse command: %w" and returned without running anything. This is a pre-execution validation failure, so no side effects occur.
Source
Thrown at internal/shell/run.go:83
}
}()
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 {
return fmt.Errorf("could not run command: %w", err)
}
return runner.Run(ctx, line)
}
// CaptureResult holds the combined output and exit code from a
// captured shell execution.
type CaptureResult struct {
Output string
ExitCode int
}
// PersistFunc is a callback that persists a shell command result.View on GitHub (pinned to 7944b8e522)
Solutions
- Print the command string with %q and check for unbalanced quotes, parentheses, or backslashes before passing it to Run.
- Validate the command with syntax.NewParser().Parse(strings.NewReader(cmd), "") yourself first and surface a precise parse-error position.
- If the command needs multiline constructs (if/for/heredocs), ensure all open blocks are closed in the same string passed to Run.
- If the command was intended to run a binary directly, pass argument arrays instead of building a shell string.
Example fix
// before
shell.Run(ctx, shell.RunOpts{Command: "echo \"hello"}) // unterminated quote
// after
shell.Run(ctx, shell.RunOpts{Command: "echo \"hello\""}) Defensive patterns
Strategy: validation
Validate before calling
func validShell(cmd string) bool {
_, err := syntax.NewParser().Parse(strings.NewReader(cmd), "")
return err == nil
}
if !validShell(opts.Command) { /* fix quoting before Run */ } Try / catch
if err := shell.Run(ctx, opts); err != nil {
var pe *parseErr // inspect wrapped error via errors.Unwrap / %v
if strings.HasPrefix(err.Error(), "could not parse command") {
// surface err to the user as invalid input, not a runtime failure
}
} Prevention
- Always single/double-quote interpolated variables in command strings.
- Validate commands with syntax.NewParser().Parse in unit tests for every template-generated command.
- Prefer passing argument arrays over concatenating shell strings.
- Lint generated multi-line scripts for balanced if/fi, for/done pairs.
When it happens
Trigger: Calling shell.Run (or opts.Command supplied to it) with a string that is not valid POSIX shell: unterminated single/double quotes, unclosed if/for/heredoc, stray 'fi'/'done', invalid redirection syntax, or a trailing backslash with nothing following.
Common situations: Developers interpolating user input or template variables into command strings and accidentally breaking quoting; multi-line commands assembled programmatically where a line continuation or heredoc terminator is missing; commands copy-pasted with smart quotes.
Related errors
- could not parse command: %w
- empty shebang
- env: missing program name
- env -S requires a program
- empty command
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/e5f66f4b95d5230a.
Report an issue: GitHub.