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

  1. Print the command string with %q and check for unbalanced quotes, parentheses, or backslashes before passing it to Run.
  2. Validate the command with syntax.NewParser().Parse(strings.NewReader(cmd), "") yourself first and surface a precise parse-error position.
  3. If the command needs multiline constructs (if/for/heredocs), ensure all open blocks are closed in the same string passed to Run.
  4. 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

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


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/e5f66f4b95d5230a. Report an issue: GitHub.