JuliusBrussee/caveman · error
kms: returned HTTP
Error message
kms: %s returned HTTP %d
What it means
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).
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.
Example fix
// before
err: kms: Decrypt returned HTTP 403
// after
if strings.Contains(err.Error(), "returned HTTP 403") || strings.Contains(err.Error(), "returned HTTP 401") {
if err := refreshKMSToken(ctx); err != nil { return err }
out, err = kms.Decrypt(ctx, ct) // retry once with fresh token
} Defensive patterns
Strategy: retry
Validate before calling
// preflight: confirm credentials/endpoint accept a cheap request
resp, err := http.Get(cfg.KMSEndpoint + "/health")
if err == nil && (resp.StatusCode == 401 || resp.StatusCode == 403) {
return errors.New("KMS auth rejected: refresh x-auth-token before calling Encrypt/Decrypt")
} Try / catch
if err != nil {
if strings.Contains(err.Error(), "returned HTTP 5") {
// retry with backoff: transient server-side failure
} else if strings.Contains(err.Error(), "returned HTTP 4") {
// do not retry: fix token/path/payload first
}
return err
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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.
Related errors
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/233a82240de821c3.
Report an issue: GitHub.
Appendix: source
Thrown at shared/platform/kms/kms.go:367
return fmt.Errorf("kms: encode %s request: %w", operation, err)
}
endpoint := c.apiBaseURL + "/key-manager/v1alpha1/regions/" + url.PathEscape(region) +
"/keys/" + url.PathEscape(keyID) + "/" + operation
req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, bytes.NewReader(body))
if err != nil {
return fmt.Errorf("kms: create %s request: %w", operation, err)
}
req.Header.Set("content-type", "application/json")
req.Header.Set("accept", "application/json")
req.Header.Set("x-auth-token", c.token)
resp, err := c.httpClient.Do(req)
if err != nil {
return fmt.Errorf("kms: %s request failed: %w", operation, err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
_, _ = io.Copy(io.Discard, io.LimitReader(resp.Body, 32<<10))
return fmt.Errorf("kms: %s returned HTTP %d", operation, resp.StatusCode)
}
data, err := io.ReadAll(io.LimitReader(resp.Body, maxResponseBytes+1))
if err != nil {
return fmt.Errorf("kms: read %s response: %w", operation, err)
}
if len(data) > maxResponseBytes {
return fmt.Errorf("kms: %s response exceeds limit", operation)
}
if err := json.Unmarshal(data, output); err != nil {
return fmt.Errorf("kms: decode %s response: %w", operation, err)
}
return nil
}
View on GitHub (pinned to 3ee70a1026)