{"record":{"id":"39522de5be05bf4f","repo":"benbjohnson/litestream","slug":"cannot-parse-exec-command-w","errorCode":null,"errorMessage":"cannot parse exec command: %w","messagePattern":"cannot parse exec command: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/litestream/replicate.go","lineNumber":373,"sourceCode":"\t\t\treturn fmt.Errorf(\"must specify port for bind address: %q\", c.Config.Addr)\n\t\t} else if host == \"\" {\n\t\t\thostport = net.JoinHostPort(\"localhost\", port)\n\t\t}\n\n\t\tslog.Info(\"serving metrics on\", \"url\", fmt.Sprintf(\"http://%s/metrics\", hostport))\n\t\tgo func() {\n\t\t\thttp.Handle(\"/metrics\", promhttp.Handler())\n\t\t\tif err := http.ListenAndServe(c.Config.Addr, nil); err != nil {\n\t\t\t\tslog.Error(\"cannot start metrics server\", \"error\", err)\n\t\t\t}\n\t\t}()\n\t}\n\n\t// Parse exec commands args & start subprocess.\n\tif c.Config.Exec != \"\" {\n\t\texecArgs, err := shellwords.Parse(c.Config.Exec)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"cannot parse exec command: %w\", err)\n\t\t}\n\n\t\tc.cmd = exec.CommandContext(ctx, execArgs[0], execArgs[1:]...)\n\t\tc.cmd.Env = os.Environ()\n\t\tc.cmd.Stdout = os.Stdout\n\t\tc.cmd.Stderr = os.Stderr\n\t\tif err := c.cmd.Start(); err != nil {\n\t\t\treturn fmt.Errorf(\"cannot start exec command: %w\", err)\n\t\t}\n\t\tgo func() { c.execCh <- c.cmd.Wait() }()\n\t} else if c.once {\n\t\t// Run one-shot replication in a goroutine so the caller can wait on execCh.\n\t\tgo c.runOnce(ctx)\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":355,"sourceCodeEnd":391,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/cmd/litestream/replicate.go#L355-L391","documentation":"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.","triggerScenarios":"`-exec` / config `exec:` value containing unmatched quotes, dangling escape characters, or other shell-words syntax errors, e.g. `exec: \"myapp --flag 'oops\"`.","commonSituations":"YAML quoting interacting with inner quotes; copy-pasted commands with smart quotes; complex commands better suited to a wrapper script.","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"],"exampleFix":"// before (config)\nexec: myapp --name \"prod db\n// after\nexec: myapp --name \"prod db\"","handlingStrategy":"validation","validationCode":"# sanity-check exec quoting (shell-words style)\npython3 - \"$EXEC\" <<'EOF'\nimport sys\ntry:\n    import shlex; shlex.split(sys.argv[1])\nexcept ValueError as e:\n    sys.exit(f\"bad exec string: {e}\")\nEOF","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["exec","parsing","config"],"backgroundTag":"invalid-argument-format","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}