benbjohnson/litestream · error
failed to marshal request: %w
Error message
failed to marshal request: %w
What it means
`litestream start` builds a litestream.StartRequest{Path, Timeout} and serializes it with json.Marshal before POSTing to the control socket at http://localhost/start. If marshaling fails, Run returns 'failed to marshal request' wrapping the json error. In practice this is nearly impossible for this fixed struct (all fields are JSON-encodable), so it almost always indicates an environment/runtime-level problem rather than bad user input.
Source
Thrown at cmd/litestream/start.go:60
// Create HTTP client that connects via Unix socket with timeout
clientTimeout := time.Duration(*timeout) * time.Second
client := &http.Client{
Timeout: clientTimeout,
Transport: &http.Transport{
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return net.DialTimeout("unix", *socketPath, clientTimeout)
},
},
}
req := litestream.StartRequest{
Path: dbPath,
Timeout: *timeout,
}
reqBody, err := json.Marshal(req)
if err != nil {
return fmt.Errorf("failed to marshal request: %w", err)
}
resp, err := client.Post("http://localhost/start", "application/json", bytes.NewReader(reqBody))
if err != nil {
return fmt.Errorf("failed to connect to control socket: %w", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("failed to read response: %w", err)
}
if resp.StatusCode != http.StatusOK {
var errResp litestream.ErrorResponse
if err := json.Unmarshal(body, &errResp); err == nil && errResp.Error != "" {
return fmt.Errorf("start failed: %s", errResp.Error)
}View on GitHub (pinned to 4ed7a308f6)
Solutions
- Retry the command — the failure is transient if caused by memory pressure
- Free system memory / check dmesg for OOM killer activity if it recurs
- If it persists, rebuild litestream (`go build -o bin/litestream ./cmd/litestream`) to rule out a corrupted binary
- Report to litestream issues if reproducible, including the wrapped json error text
Defensive patterns
Strategy: try-catch
Try / catch
// CLI wrapper: distinguish usage errors from transient failures
if err := litestreamStart(dbPath, timeout); err != nil {
if strings.Contains(err.Error(), "failed to marshal request") {
// transient/runtime-level: retry once, then report with wrapped cause
if retryErr := litestreamStart(dbPath, timeout); retryErr != nil {
return fmt.Errorf("start failed after retry: %w", retryErr)
}
return nil
}
return err
} Prevention
- No input validation can prevent this — the struct is fixed and encodable
- Monitor system memory if you see this error recur
- Keep the litestream binary rebuilt from a clean checkout
- Include the wrapped json error text in bug reports
When it happens
Trigger: json.Marshal returning an error for the StartRequest value. With the fixed struct (string Path, int Timeout) this only occurs under exotic runtime conditions such as memory allocation failure; it cannot be triggered by user-supplied values since both fields are plain encodable types.
Common situations: Extremely rare — encountered only during system-level resource exhaustion (OOM conditions) or a corrupted Go runtime; not caused by configuration or user input.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
- failed to parse response: %w
- failed to format response: %w
- failed to format response: %w
- failed to marshal request: %w
- failed to connect to control socket: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/c7588626adcf0b1b.
Report an issue: GitHub.