benbjohnson/litestream · error

failed to parse response: %w

Error message

failed to parse response: %w

What it means

On a 200 response, the command decodes the body into litestream.RegisterDatabaseResponse with json.Unmarshal. A decode failure means the daemon answered 200 but the body isn't the expected JSON schema; the error is wrapped as 'failed to parse response'.

Source

Thrown at cmd/litestream/register.go:93

	}
	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)
		}
		return fmt.Errorf("register failed: %s", string(body))
	}

	var result litestream.RegisterDatabaseResponse
	if err := json.Unmarshal(body, &result); err != nil {
		return fmt.Errorf("failed to parse response: %w", err)
	}

	confirmation := RegisterResult{
		Status:  result.Status,
		DBPath:  result.Path,
		Replica: replicaURL,
		Socket:  *socketPath,
	}
	if *jsonOutput {
		output, err := json.MarshalIndent(confirmation, "", "  ")
		if err != nil {
			return fmt.Errorf("failed to format response: %w", err)
		}
		fmt.Println(string(output))
		return nil
	}

	fmt.Printf("status: %s\n", registerDisplayStatus(confirmation.Status))

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Ensure CLI and daemon are the same litestream version (reinstall/restart both)
  2. Inspect the %w-wrapped cause to see the exact unmarshal error (field/type mismatch)
  3. Capture the raw body (e.g. with -json on an older CLI or by testing the socket with curl --unix-socket) to see what was actually returned
  4. Confirm the process listening on the socket is the litestream daemon
Defensive patterns

Strategy: try-catch

Validate before calling

litestream version  # verify CLI/daemon version match

Try / catch

if err := registerCmd.Run(ctx, args); err != nil {
    if strings.Contains(err.Error(), "failed to parse response") {
        // 200 but malformed JSON: capture cause, compare versions
        log.Printf("bad response from daemon: %v", errors.Unwrap(err))
    }
}

Prevention

When it happens

Trigger: Daemon returns 200 with empty body, truncated JSON, or fields of unexpected types (e.g. status as a number); version mismatch between CLI and daemon changing the response schema; something other than the litestream daemon listening on the socket.

Common situations: Mixed litestream versions after an upgrade (old daemon, new CLI); custom reverse proxies or socket shims; daemon handler bug producing malformed JSON with a 200 status.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


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