{"record":{"id":"07533565a6e179ae","repo":"benbjohnson/litestream","slug":"cannot-start-exec-command-w","errorCode":null,"errorMessage":"cannot start exec command: %w","messagePattern":"cannot start exec command: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/litestream/replicate.go","lineNumber":381,"sourceCode":"\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\n// runOnce performs one-shot replication for all databases.\n// It syncs all databases, optionally takes snapshots, and enforces retention.\nfunc (c *ReplicateCommand) runOnce(ctx context.Context) {\n\tvar err error\n\tdefer func() { c.execCh <- err }()\n\n\tfor _, db := range c.Store.DBs() {\n\t\tslog.Info(\"syncing database\", \"path\", db.Path())","sourceCodeStart":363,"sourceCodeEnd":399,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/cmd/litestream/replicate.go#L363-L399","documentation":"After parsing the exec string, Run builds an exec.CommandContext and starts the subprocess. If cmd.Start fails (binary not found in PATH, not executable, missing interpreter), the error is wrapped as \"cannot start exec command\". Litestream exits rather than replicating without its supervised process.","triggerScenarios":"`exec.CommandContext(...).Start()` returns error in Run — command name not in PATH, file lacks execute permission, shebang interpreter missing, or working directory invalid.","commonSituations":"Container images where the app binary isn't installed or isn't in PATH; relative paths resolved against an unexpected working directory; permission bits lost after copying files.","solutions":["Verify the command exists in PATH for the litestream process (`which <cmd>` as the same user)","Use an absolute path in exec and ensure the execute bit is set (chmod +x)","Check the script's shebang interpreter exists in the image","Ensure litestream runs as a user with permission to execute the command"],"exampleFix":"// before (config)\nexec: myapp\n// after\nexec: /usr/local/bin/myapp  # chmod +x /usr/local/bin/myapp","handlingStrategy":"try-catch","validationCode":"CMD=$(yq '.exec' litestream.yml)\nBIN=$(echo \"$CMD\" | awk '{print $1}')\ncommand -v \"$BIN\" >/dev/null || { echo \"exec binary not found: $BIN\" >&2; exit 1; }\n[ -x \"$BIN\" ] || { echo \"exec binary not executable: $BIN\" >&2; exit 1; }","typeGuard":null,"tryCatchPattern":"if err := cmd.Run(ctx); err != nil {\n    if strings.Contains(err.Error(), \"cannot start exec command\") {\n        log.Fatalf(\"exec subprocess failed to start: %v\", err)\n    }\n    return err\n}","preventionTips":["Install the supervised binary in the same image/container as litestream","Use absolute paths for exec commands","Verify execute permissions and shebang interpreters in CI/image builds","Run litestream under a user that can execute the target command"],"tags":["exec","subprocess","startup"],"backgroundTag":"command-not-found","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}