{"record":{"id":"233a82240de821c3","repo":"JuliusBrussee/caveman","slug":"kms-s-returned-http-d","errorCode":null,"errorMessage":"kms: %s returned HTTP %d","messagePattern":"kms: (.+?) returned HTTP (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/platform/kms/kms.go","lineNumber":367,"sourceCode":"\t\treturn fmt.Errorf(\"kms: encode %s request: %w\", operation, err)\n\t}\n\tendpoint := c.apiBaseURL + \"/key-manager/v1alpha1/regions/\" + url.PathEscape(region) +\n\t\t\"/keys/\" + url.PathEscape(keyID) + \"/\" + operation\n\treq, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, bytes.NewReader(body))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"kms: create %s request: %w\", operation, err)\n\t}\n\treq.Header.Set(\"content-type\", \"application/json\")\n\treq.Header.Set(\"accept\", \"application/json\")\n\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":349,"sourceCodeEnd":381,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/shared/platform/kms/kms.go#L349-L381","documentation":"The KMS HTTP endpoint responded with a status code other than 200. The client discards up to 32KB of the response body and returns this error carrying the operation name and actual status code. It means the request reached the KMS server but the server rejected it or returned an unexpected status (auth failure, bad request, server error).","triggerScenarios":"Encrypt or Decrypt calls where the KMS server returns 401/403 (invalid or expired x-auth-token), 404 (wrong path), 400 (malformed request payload), or 5xx (server-side failure).","commonSituations":"Expired or rotated KMS auth token not refreshed in config, wrong API path for the KMS deployment version, sending a request to a load balancer returning 502/503, or insufficient permissions for the key being used.","solutions":["Read the status code from the error string and check the KMS server logs for the corresponding request to learn the rejection reason.","Verify the x-auth-token is current and valid; rotate/refresh credentials if expired.","Confirm the request payload and endpoint path match the KMS API version deployed.","For 5xx responses, retry with backoff; the failure may be transient on the server side.","Check RBAC/key ACLs on the KMS side if the status is 403."],"exampleFix":"// before\nerr: kms: Decrypt returned HTTP 403\n// after\nif strings.Contains(err.Error(), \"returned HTTP 403\") || strings.Contains(err.Error(), \"returned HTTP 401\") {\n    if err := refreshKMSToken(ctx); err != nil { return err }\n    out, err = kms.Decrypt(ctx, ct) // retry once with fresh token\n}","handlingStrategy":"retry","validationCode":"// preflight: confirm credentials/endpoint accept a cheap request\nresp, err := http.Get(cfg.KMSEndpoint + \"/health\")\nif err == nil && (resp.StatusCode == 401 || resp.StatusCode == 403) {\n    return errors.New(\"KMS auth rejected: refresh x-auth-token before calling Encrypt/Decrypt\")\n}","typeGuard":null,"tryCatchPattern":"if err != nil {\n    if strings.Contains(err.Error(), \"returned HTTP 5\") {\n        // retry with backoff: transient server-side failure\n    } else if strings.Contains(err.Error(), \"returned HTTP 4\") {\n        // do not retry: fix token/path/payload first\n    }\n    return err\n}","preventionTips":["Automate token refresh before expiry; never hardcode long-lived tokens.","Pin and test against the deployed KMS API version.","Alert on 4xx/5xx rates from the KMS endpoint.","Validate request payloads against the API schema before sending."],"tags":["http","kms","api","go"],"backgroundTag":"http-non-200-response","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"}