benbjohnson/litestream · error
cannot start exec command: %w
Error message
cannot start exec command: %w
What it means
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.
Source
Thrown at cmd/litestream/replicate.go:381
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
}
// runOnce performs one-shot replication for all databases.
// It syncs all databases, optionally takes snapshots, and enforces retention.
func (c *ReplicateCommand) runOnce(ctx context.Context) {
var err error
defer func() { c.execCh <- err }()
for _, db := range c.Store.DBs() {
slog.Info("syncing database", "path", db.Path())View on GitHub (pinned to 4ed7a308f6)
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
Example fix
// before (config) exec: myapp // after exec: /usr/local/bin/myapp # chmod +x /usr/local/bin/myapp
Defensive patterns
Strategy: try-catch
Validate before calling
CMD=$(yq '.exec' litestream.yml)
BIN=$(echo "$CMD" | awk '{print $1}')
command -v "$BIN" >/dev/null || { echo "exec binary not found: $BIN" >&2; exit 1; }
[ -x "$BIN" ] || { echo "exec binary not executable: $BIN" >&2; exit 1; } Try / catch
if err := cmd.Run(ctx); err != nil {
if strings.Contains(err.Error(), "cannot start exec command") {
log.Fatalf("exec subprocess failed to start: %v", err)
}
return err
} Prevention
- 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
When it happens
Trigger: `exec.CommandContext(...).Start()` returns error in Run — command name not in PATH, file lacks execute permission, shebang interpreter missing, or working directory invalid.
Common situations: 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.
Related errors
- %w: %s
- failed to configure replica %d for %s: %w
- cannot open store: %w
- start directory monitor for %s: %w
- cannot parse exec command: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/07533565a6e179ae.
Report an issue: GitHub.