charmbracelet/crush · error
parse: %w
Error message
parse: %w
What it means
ExpandValue failed to parse its input as a shell document word. ExpandValue expands a config-style string with full $VAR, ${VAR...}, and $(...) support by parsing it with syntax.NewParser().Document; input containing shell metacharacters ($ ` \ ' ") that is not valid shell word syntax produces this wrapped parse error.
Source
Thrown at internal/shell/expand.go:76
// - Errors wrap the failing inner command's exit code and a bounded
// prefix of its stderr. Callers that surface the error to users
// should additionally scrub it for the original template text.
func ExpandValue(ctx context.Context, value string, env []string) (string, error) {
// Fast path: a value with no shell metacharacters expands to itself.
// Parsing and running it through the interpreter would produce the
// same string at significant cost. Most config values (literal API
// keys, fixed URLs) hit this path, which matters because ExpandValue
// runs over every provider/MCP/LSP value on each config reload.
if !strings.ContainsAny(value, "$`\\'\"") {
return value, nil
}
// Parse the value as a here-doc style word: no word splitting, no
// globbing, but full support for $VAR, ${VAR...}, $(...), and
// quoted/escaped strings.
word, err := syntax.NewParser().Document(strings.NewReader(value))
if err != nil {
return "", fmt.Errorf("parse: %w", err)
}
// Build a minimal Shell value purely to reuse its handler chain
// (builtins, block funcs, optional Go coreutils) inside $(...).
// We deliberately skip NewShell so the passed-in env is used
// verbatim, with no CRUSH/AGENT/AI_AGENT injection: callers of
// ExpandValue control the env, and nounset must treat any name
// not in env as unset.
//
// The working directory is only needed for $(...) command
// substitution, so we resolve it lazily on first use. Values that
// only reference variables or use quoting (the common case) avoid
// the os.Getwd() syscall entirely.
s := &Shell{
env: env,
logger: noopLogger{},
}
cwdResolved := falseView on GitHub (pinned to 7944b8e522)
Solutions
- Fix the shell syntax in the value: balance quotes and parentheses, close ${...} expansions.
- Escape literal metacharacters: prefix $ ` " ' \ with a backslash so they expand to themselves.
- If the value must be taken literally, remove the special characters from the config entirely.
- Test the value with `echo '<value>'` in a real shell to confirm it parses.
Example fix
// before ExpandValue(ctx, "pass\word$", env) // after ExpandValue(ctx, "pass\\word$", env)
Defensive patterns
Strategy: validation
Validate before calling
// cheap pre-check mirroring the parser's needs
if strings.Count(v, "$")%2 != 0 || strings.Count(v, "(") != strings.Count(v, ")") {
return fmt.Errorf("unbalanced expansion syntax in %q", v)
} Try / catch
expanded, err := shell.ExpandValue(ctx, value, env)
if err != nil && strings.HasPrefix(err.Error(), "parse: ") {
// invalid shell syntax in config value
} Prevention
- Escape literal $ ` " ' \ characters in config values.
- Test expansion-heavy values in a real shell first.
- Prefer plain values without metacharacters when expansion is not needed.
- Validate config with a shell-syntax linter at load time.
When it happens
Trigger: Calling shell.ExpandValue(ctx, value, env) with a value containing metacharacters that don't parse as a shell word — e.g. an unclosed quote, an unterminated $(, or a stray backslash; values without metacharacters take the fast path and never parse.
Common situations: Config values with literal quotes or dollars that were meant verbatim but are invalid shell syntax; API keys or secrets pasted with special characters; YAML/JSON config strings with accidental backslashes; typos like ${VAR (missing brace).
Related errors
- unsupported env flag: %s
- could not parse %s: %w
- could not build runner for %s: %w
- requested channels differ from the existing workspace; chann
- empty shebang
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/7568b9007bcbc572.
Report an issue: GitHub.