kopia/kopia · error

unable to parse JSON response

Error message

unable to parse JSON response

What it means

decodeResponse decodes the response body as JSON into the caller-provided pointer. This error means the body is not valid JSON or does not decode into the target type — commonly because the server returned an HTML error page, an empty body, or the caller's target struct does not match the actual payload.

Solutions

  1. Dump the raw response body/status to see what was actually returned
  2. Verify the request is reaching the Kopia API server, not a proxy or different service
  3. Check server/client version compatibility of the API DTOs
  4. If the body may legitimately be empty, use a *[]byte target instead
  5. Confirm authentication succeeded — some servers return non-JSON auth errors
Defensive patterns

Strategy: type-guard

Validate before calling

resp, err := http.Get(url)
if err != nil { return err }
ct := resp.Header.Get("Content-Type")
if !strings.HasPrefix(ct, "application/json") {
    return fmt.Errorf("expected JSON, got %q status %d", ct, resp.StatusCode)
}

Type guard

func isJSONResponse(h http.Header) bool {
    return strings.HasPrefix(h.Get("Content-Type"), "application/json")
}

Try / catch

if err != nil && strings.Contains(err.Error(), "parse JSON response") {
    // log status + raw body snippet for diagnosis
}

Prevention

When it happens

Trigger: Any API call whose expected respPayload is a JSON struct while the server returns non-JSON: an HTML 502/503 page from a proxy, plain-text error, empty 200 body, or a schema mismatch (field type changed).

Common situations: Hitting the wrong port so a different service answers; proxy error pages; Kopia server version older/newer than the client DTOs expect; unauthenticated captive-portal or login page responses.

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 kopia/kopia@82495e54b5 (2026-09-07). Data as JSON: /api/errors/ad22e8083711e106. Report an issue: GitHub.

Appendix: source

Thrown at internal/apiclient/apiclient.go:190

func decodeResponse(resp *http.Response, respPayload any) error {
	if resp.StatusCode != http.StatusOK {
		return HTTPStatusError{resp.StatusCode, respToErrorMessage(resp)}
	}

	if respPayload == nil {
		return nil
	}

	if b, ok := respPayload.(*[]byte); ok {
		v, err := io.ReadAll(resp.Body)
		if err != nil {
			return errors.Wrap(err, "unable to read response")
		}

		*b = v
	} else if err := json.NewDecoder(resp.Body).Decode(respPayload); err != nil {
		return errors.Wrap(err, "unable to parse JSON response")
	}

	return nil
}

// Options encapsulates all optional parameters for KopiaAPIClient.
type Options struct {
	BaseURL string

	Username string
	Password string

	TrustedServerCertificateFingerprint string

	LogRequests bool
}

// NewKopiaAPIClient creates a client for connecting to Kopia HTTP API.

View on GitHub (pinned to 82495e54b5)