benbjohnson/litestream · error
cannot parse exec command: %w
Error message
cannot parse exec command: %w
What it means
The `-exec` option value is parsed with shellwords.Parse to split it into a command and arguments. If the string has unbalanced quotes or malformed shell-like syntax, parsing fails and Run returns this error with the underlying shellwords error wrapped.
Source
Thrown at cmd/litestream/replicate.go:373
return fmt.Errorf("must specify port for bind address: %q", c.Config.Addr)
} else if host == "" {
hostport = net.JoinHostPort("localhost", port)
}
slog.Info("serving metrics on", "url", fmt.Sprintf("http://%s/metrics", hostport))
go func() {
http.Handle("/metrics", promhttp.Handler())
if err := http.ListenAndServe(c.Config.Addr, nil); err != nil {
slog.Error("cannot start metrics server", "error", err)
}
}()
}
// Parse exec commands args & start subprocess.
if c.Config.Exec != "" {
execArgs, err := shellwords.Parse(c.Config.Exec)
if err != nil {
return fmt.Errorf("cannot parse exec command: %w", err)
}
c.cmd = exec.CommandContext(ctx, execArgs[0], execArgs[1:]...)
c.cmd.Env = os.Environ()
c.cmd.Stdout = os.Stdout
c.cmd.Stderr = os.Stderr
if err := c.cmd.Start(); err != nil {
return fmt.Errorf("cannot start exec command: %w", err)
}
go func() { c.execCh <- c.cmd.Wait() }()
} else if c.once {
// Run one-shot replication in a goroutine so the caller can wait on execCh.
go c.runOnce(ctx)
}
return nil
}
View on GitHub (pinned to 4ed7a308f6)
Solutions
- Fix quoting in the exec string (balanced single/double quotes, no smart quotes)
- Simplify by pointing exec at a shell script: `exec: /bin/run-app.sh`
- Test the string with a shell-words parser or `sh -c` equivalent before adding it to config
Example fix
// before (config) exec: myapp --name "prod db // after exec: myapp --name "prod db"
Defensive patterns
Strategy: validation
Validate before calling
# sanity-check exec quoting (shell-words style)
python3 - "$EXEC" <<'EOF'
import sys
try:
import shlex; shlex.split(sys.argv[1])
except ValueError as e:
sys.exit(f"bad exec string: {e}")
EOF Prevention
- Prefer a wrapper script path over complex inline commands
- Keep exec strings in config free of nested/unbalanced quotes
- Avoid smart quotes from copy-paste; use plain ASCII quotes
- Test the exec string with shlex/shellwords parsing in CI
When it happens
Trigger: `-exec` / config `exec:` value containing unmatched quotes, dangling escape characters, or other shell-words syntax errors, e.g. `exec: "myapp --flag 'oops"`.
Common situations: YAML quoting interacting with inner quotes; copy-pasted commands with smart quotes; complex commands better suited to a wrapper script.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- parse replica url: %w
- invalid size format: %w
- heartbeat URL must be a valid HTTP or HTTPS URL
- heartbeat interval must be at least 1 minute
- config file not found
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/39522de5be05bf4f.
Report an issue: GitHub.