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

  1. Read the wrapped error: 'unexpected EOF'/'connection reset' suggests intermediary timeouts; 'context canceled' means your ctx ended
  2. Retry the operation — mid-body failures are characteristically transient
  3. If it recurs, raise intermediary (LB/proxy) response timeouts on the KMS route
  4. 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

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


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/38c0471d8b3c8ee1. Report an issue: GitHub.