benbjohnson/litestream · error

failed to parse response: %w

Error message

failed to parse response: %w

What it means

On HTTP 200, Run unmarshals the body into litestream.InfoResponse. If json.Unmarshal fails, the response was not valid JSON or did not match the InfoResponse schema, and Run wraps the error with this message. It signals a client/server contract mismatch or corrupted payload.

Source

Thrown at cmd/litestream/info.go:69

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

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

	if *jsonOutput {
		output, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return fmt.Errorf("failed to format response: %w", err)
		}
		fmt.Println(string(output))
	} else {
		uptime := time.Duration(result.UptimeSeconds) * time.Second
		fmt.Printf("Litestream %s\n", result.Version)
		fmt.Printf("  PID:        %d\n", result.PID)
		fmt.Printf("  Uptime:     %s\n", uptime)
		fmt.Printf("  Started at: %s\n", result.StartedAt.Format(time.RFC3339))
		fmt.Printf("  Databases:  %d\n", result.DatabaseCount)
	}

	return nil

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Restart the daemon so it matches the installed CLI version, then retry.
  2. Check `litestream version` (daemon logs) versus your CLI version and align them.
  3. Inspect the raw endpoint output (curl the /info endpoint) to see what is actually returned.
  4. Remove intermediaries that could rewrite or truncate the response body.

Example fix

// before
$ litestream version  # v0.5 CLI
$ ps  # daemon still old binary from before upgrade
// after
$ systemctl restart litestream  # daemon now runs new binary
$ litestream info
Defensive patterns

Strategy: try-catch

Validate before calling

// verify versions before calling
const { stdout } = await exec('litestream version');
const daemonVersion = await readDaemonVersionFromLogs();
if (stdout.trim() !== daemonVersion.trim()) throw new Error('CLI/daemon version mismatch; restart daemon');

Try / catch

var result litestream.InfoResponse
if err := json.Unmarshal(body, &result); err != nil {
    // contract mismatch or corrupt payload: dump body, restart daemon to align versions, retry
    log.Printf("bad /info payload: %v; body=%q", err, body)
    return retryAfterDaemonRestart()
}

Prevention

When it happens

Trigger: Daemon returns 200 with an empty or malformed body; the running daemon is an older/newer version whose /info JSON schema differs from the CLI's InfoResponse struct; a proxy mangles the body.

Common situations: Upgraded CLI binary while the daemon process still runs an older version; partial response truncated at a JSON boundary (rare); custom builds where the endpoint output changed.

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/962681eef64af9ac. Report an issue: GitHub.