benbjohnson/litestream · error

failed to marshal request: %w

Error message

failed to marshal request: %w

What it means

Before POSTing to the control socket, the register command serializes the RegisterDatabaseRequest (path + replica URL) with encoding/json. If json.Marshal fails, the request is wrapped as 'failed to marshal request'. In practice this is nearly impossible here because the payload contains only plain strings, so it signals a genuine internal invariant violation rather than user error.

Source

Thrown at cmd/litestream/register.go:69

	// 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.RegisterDatabaseRequest{
		Path:       dbPath,
		ReplicaURL: replicaURL,
	}
	reqBody, err := json.Marshal(req)
	if err != nil {
		return fmt.Errorf("failed to marshal request: %w", err)
	}

	resp, err := client.Post("http://localhost/register", "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("register failed: %s", errResp.Error)
		}

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Verify you are running an unmodified litestream build (rebuild from source)
  2. Inspect the wrapped %w cause for the actual json.UnsupportedTypeError and check any custom MarshalJSON on RegisterDatabaseRequest
  3. If reproducible in a fork, ensure added fields are JSON-encodable
Defensive patterns

Strategy: try-catch

Try / catch

if err := registerCmd.Run(ctx, args); err != nil {
    var e *fmt.wrapError
    if errors.As(err, &e) && strings.Contains(err.Error(), "failed to marshal request") {
        log.Fatalf("internal bug: non-marshalable request field: %v", err)
    }
}

Prevention

When it happens

Trigger: A json.Marshal failure on the RegisterDatabaseRequest struct — only reachable if the struct fields become unsupported types (e.g. channels/funcs/cycles) in a modified build; not reachable with string fields in the current code.

Common situations: Almost never hit by end users; may appear if a fork or patch adds a non-marshalable field to RegisterDatabaseRequest, or a custom json.Marshaler on it returns an error.

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


AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06). Data as JSON: /api/errors/570e8409eb969de2. Report an issue: GitHub.