{"record":{"id":"ea08ff114cfb8225","repo":"JuliusBrussee/caveman","slug":"kms-decode-s-response-w","errorCode":null,"errorMessage":"kms: decode %s response: %w","messagePattern":"kms: decode (.+?) response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/platform/kms/kms.go","lineNumber":377,"sourceCode":"\treq.Header.Set(\"x-auth-token\", c.token)\n\tresp, err := c.httpClient.Do(req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"kms: %s request failed: %w\", operation, err)\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\t_, _ = io.Copy(io.Discard, io.LimitReader(resp.Body, 32<<10))\n\t\treturn fmt.Errorf(\"kms: %s returned HTTP %d\", operation, resp.StatusCode)\n\t}\n\tdata, err := io.ReadAll(io.LimitReader(resp.Body, maxResponseBytes+1))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"kms: read %s response: %w\", operation, err)\n\t}\n\tif len(data) > maxResponseBytes {\n\t\treturn fmt.Errorf(\"kms: %s response exceeds limit\", operation)\n\t}\n\tif err := json.Unmarshal(data, output); err != nil {\n\t\treturn fmt.Errorf(\"kms: decode %s response: %w\", operation, err)\n\t}\n\treturn nil\n}\n","sourceCodeStart":359,"sourceCodeEnd":381,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/shared/platform/kms/kms.go#L359-L381","documentation":"The KMS response body was read successfully but could not be decoded as the expected JSON shape into the output struct. The client unmarshals the limited body and wraps any json.Unmarshal failure with the operation name. HTTP 200 was returned but the payload is not valid JSON or has an unexpected schema.","triggerScenarios":"Encrypt or Decrypt calls where the endpoint returns non-JSON (HTML error pages behind a 200, plaintext), or the KMS API response schema changed/does not match the client's output struct fields/types.","commonSituations":"Misrouted endpoint returning a login page or SPA HTML with status 200, KMS server version upgrade changing field names/types, a proxy intercepting and rewriting responses, or version skew between client structs and server API.","solutions":["Dump the raw response body (curl the endpoint) to see what is actually being returned — HTML means wrong endpoint/proxy interception.","Pin and align client and server KMS API versions; check the server changelog for response schema changes.","Verify the output struct tags match the server's JSON field names.","Ensure Content-Type of the response is application/json before parsing.","If the server is behind an auth gateway, check that requests aren't being redirected to a login page with a 200."],"exampleFix":"// before\nvar out kms.DecryptOutput\nif err := client.Decrypt(ctx, ct); err != nil { /* kms: decode Decrypt response: invalid character '<' */ }\n// after\nresp, _ := http.Get(cfg.KMSEndpoint + \"/health\") // sanity check endpoint returns JSON\nct := resp.Header.Get(\"Content-Type\")\nif !strings.HasPrefix(ct, \"application/json\") {\n    log.Fatalf(\"KMS endpoint not returning JSON (content-type %q); check URL/proxy\", ct)\n}","handlingStrategy":"type-guard","validationCode":"// probe the endpoint returns JSON before using the client\nresp, _ := http.Get(cfg.KMSEndpoint + \"/health\")\nif resp != nil && !strings.HasPrefix(resp.Header.Get(\"Content-Type\"), \"application/json\") {\n    return errors.New(\"KMS endpoint is not serving JSON — check URL/proxy\")\n}","typeGuard":"func looksLikeJSON(b []byte) bool {\n    s := bytes.TrimSpace(b)\n    return len(s) > 0 && (s[0] == '{' || s[0] == '[')\n}","tryCatchPattern":"if err != nil && strings.HasPrefix(err.Error(), \"kms: decode \") {\n    // capture raw body for diagnosis; check server/client API version skew\n    return fmt.Errorf(\"unexpected KMS response schema: %w\", err)\n}","preventionTips":["Keep client structs and server API version in lockstep; test against the real server in CI.","Check response Content-Type before parsing.","Beware auth gateways returning 200 HTML login pages behind misconfigured proxies.","Add a JSON schema test for KMS responses on every server upgrade."],"tags":["json","kms","api","go"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}