api: client-disconnect body-read failures are misclassified as auth errors (400 WARN noise)
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 1.6k
- Forks
- 438
- PR merge metrics
- No merged PRs in 30d
Description
Problem
Under high concurrency (e.g. 1 000 simultaneous sandbox creates after a period of idleness), the orchestration-api emits a flood of WARN log lines and 400 responses that look like authentication failures:
WARN error in openapi3filter.SecurityRequirementsError: security requirements failed: reading failed: read tcp 192.168.0.146:3000->100.64.x.x:port: i/o timeout
WARN error in openapi3filter.SecurityRequirementsError: security requirements failed: reading failed: read tcp 192.168.0.146:3000->100.64.x.x:port: connection reset by peer
These are not auth failures. They are network-level events where either:
- the server's
ReadTimeout: 10sexpired while the goroutine was queued waiting to be scheduled (under heavy load), or - the client SDK's own timeout fired and closed the connection before the server read the body.
Root cause
kin-openapi@v0.139.0 (openapi3filter/validate_request.go:448) reads the entire request body via io.ReadAll before calling any AuthenticationFunc. When that TCP read fails it returns:
&RequestError{Reason: "reading failed", Err: <net.Error>}
validateSecurityRequirements then wraps this in SecurityRequirementsError. processCustomErrors in packages/api/internal/utils/error.go has no special handling for this case, so it falls through to the generic securityErrPrefix path. ErrorHandler then calls telemetry.ReportError (sets OTel span error status → WARN log line), adds to c.Errors, and returns HTTP 400 — all of which suggest an auth failure to every downstream observer: dashboards, alerts, on-call.
Impact
- Auth-failure dashboards and alerts fire on client-side network noise.
- Incident responders waste time investigating fake 401/400 spikes.
- Real auth failures are diluted by the noise, increasing MTTD.
Fix
In processCustomErrors, detect RequestError{Reason:"reading failed"} with an underlying net.Error and return it under a dedicated clientDisconnectPrefix. ErrorHandler handles this prefix early: records an OTel span event (informational, not error status) via telemetry.ReportEvent, and responds 499 without adding to c.Errors.
Result:
- No more fake
SecurityRequirementsErrorWARN logs for client disconnects. - 499 responses are queryable in metrics separately from 400/401/403.
- Auth-failure alerts stay clean.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in packages/api/internal/utils/error.go, tracing processCustomErrors and ErrorHandler, then review the request-body failure described at kin-openapi/openapi3filter/validate_request.go:448. Verify how telemetry.ReportError, telemetry.ReportEvent, c.Errors, and response status are currently used. Done means client-disconnect body-read failures are separated from authentication errors and produce the described 499 behavior without error-status logging.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- backend-api-design, networking, observability
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 70/100