JuliusBrussee/caveman · error
kms: read %s response: %w
Error message
kms: read %s response: %w
What it means
After a 200 response, the helper reads the body with io.ReadAll(io.LimitReader(resp.Body, maxResponseBytes+1)) (cap 512 KiB); a read error is wrapped as 'kms: read %s response: %w'. This means the connection broke mid-body: unexpected EOF, connection reset, or the context being cancelled while the body streamed. It is rare relative to 1197/1198 because headers already succeeded.
Source
Thrown at shared/platform/kms/kms.go:371
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 27d5a3981a)
Solutions
- Read the wrapped error: 'unexpected EOF'/'connection reset' suggests intermediary timeouts; 'context canceled' means your ctx ended
- Retry the operation — mid-body failures are characteristically transient
- If it recurs, raise intermediary (LB/proxy) response timeouts on the KMS route
- Avoid sharing a short-lived request context with KMS calls; derive one with its own deadline
Example fix
// before ctx, cancel := context.WithTimeout(req.Context(), 300*time.Millisecond) defer cancel() pt, err := client.Encrypt(ctx, plaintext) // after ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() pt, err := client.Encrypt(ctx, plaintext)
Defensive patterns
Strategy: retry
Validate before calling
null
Try / catch
pt, err := client.Encrypt(ctx, plaintext)
if err != nil && strings.Contains(err.Error(), "read ") && strings.Contains(err.Error(), " response: ") {
pt, err = client.Encrypt(ctx, plaintext) // mid-body read failures are transient; one retry
} Prevention
- Derive KMS contexts with their own deadline instead of reusing request contexts
- Raise LB/proxy response timeouts on routes to the KMS API
- Retry once on mid-body read errors before surfacing to callers
When it happens
Trigger: Connection reset between response headers and body completion (LB idle timeout, proxy interruption); caller's context cancelled during body read; TLS session torn down mid-stream; oversized body exceeding the reader returning io.ErrUnexpectedEOF in edge cases.
Common situations: Load balancers with aggressive response timeouts cutting long KMS responses; mobile/unstable network edges; shared contexts cancelled by request handlers ending early; proxies buffering inconsistently.
Related errors
- kms: %s request failed: %w
- invalid listen address %q: %w
- Claude usage request failed with HTTP %d
- production KMS configuration: %w
- kms: unsupported provider %q
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/38c0471d8b3c8ee1.
Report an issue: GitHub.