charmbracelet/crush · error
could not parse command: %w
Error message
could not parse command: %w
What it means
Shell.execCommon (used by both exec and execStream) parses the command string with syntax.NewParser().Parse before interpreting it. A parse failure is wrapped as "could not parse command: %w" and the command is never executed. Functionally identical to error 670 but on the persistent Shell type rather than the stateless Run() helper.
Source
Thrown at internal/shell/shell.go:273
}
}
// execCommon is the shared implementation for executing commands
func (s *Shell) execCommon(ctx context.Context, command string, stdout, stderr io.Writer) (err error) {
var runner *interp.Runner
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("command execution panic: %v", r)
}
if runner != nil {
s.updateShellFromRunner(runner)
}
s.logger.InfoPersist("command finished", "command", command, "err", err)
}()
line, err := syntax.NewParser().Parse(strings.NewReader(command), "")
if err != nil {
return fmt.Errorf("could not parse command: %w", err)
}
runner, err = s.newInterp(nil, stdout, stderr)
if err != nil {
return fmt.Errorf("could not run command: %w", err)
}
err = runner.Run(ctx, line)
return err
}
// exec executes commands using a cross-platform shell interpreter.
func (s *Shell) exec(ctx context.Context, command string) (string, string, error) {
var stdout, stderr bytes.Buffer
err := s.execCommon(ctx, command, &stdout, &stderr)
return stdout.String(), stderr.String(), err
}
View on GitHub (pinned to 7944b8e522)
Solutions
- Inspect the wrapped mvdan/sh parse error, which includes line/column of the syntax problem.
- Fix quoting: wrap variables in double quotes, use single quotes for literal strings.
- Validate the command standalone with syntax.NewParser().Parse before handing it to the shell.
- Split complex multi-line scripts and execute them stepwise to isolate the broken segment.
Example fix
// before sh.Exec(ctx, "for f in *.go; do echo $f") // missing done // after sh.Exec(ctx, "for f in *.go; do echo \"$f\"; done")
Defensive patterns
Strategy: validation
Validate before calling
func validShell(cmd string) bool {
_, err := syntax.NewParser().Parse(strings.NewReader(cmd), "")
return err == nil
} Try / catch
err := sh.Exec(ctx, cmd)
if err != nil && strings.HasPrefix(err.Error(), "could not parse command") {
// return as invalid-input to user/agent; include wrapped position info
} Prevention
- Quote all variable expansions: "$var" not $var.
- Run generated commands through a parse check in CI before shipping prompts/tools.
- Close all heredocs and control-flow blocks within the same command string.
- Reject user-pasted snippets that fail parsing instead of passing them through.
When it happens
Trigger: Passing shell-invalid source to Shell.exec/execStream: unclosed quotes, unmatched fi/done/esac, invalid parameter expansion like ${var, bad redirection targets, or incomplete command substitution $( without closing.
Common situations: Agent/tool-generated commands with broken quoting; template rendering bugs producing half-formed shell; users pasting multi-line snippets into the TUI where a heredoc terminator got lost.
Related errors
- empty command
- shell.Run: Cwd is required
- could not parse command: %w
- prompt is required
- session id missing from context
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/52d9b8a7f51981f8.
Report an issue: GitHub.