Skip to content

gRPC client maps post-deadline transport errors to internal instead of deadline_exceeded #210

Description

@iainmcgin

The gRPC client conformance suite (task conformance:test-client-grpc-only) intermittently fails Timeouts/* test cases when the host has scheduling jitter (a shared-tenancy VM reproduces it readily; CI runners rarely do). Repeated runs of only the Timeouts cases show a ~2-3% per-case failure rate on such a host, at the same rate on main as on a feature branch, so this is a long-standing race rather than a recent regression:

FAILED: Timeouts/HTTPVersion:2/Protocol:PROTOCOL_GRPC/Codec:CODEC_PROTO/Compression:COMPRESSION_IDENTITY/TLS:false/(grpc server impl)/server-stream:
    actual error {code: 13 (internal), message: "error reading response body: error reading a body from connection"} does not match expected code 4 (deadline_exceeded)

The race: the client enforces its deadline with tokio::time::timeout_at (with_deadline, connectrpc/src/client/mod.rs:1317), and the reference grpc-go server independently aborts the RPC when the same deadline expires server-side. When the server's RST_STREAM arrives before the local timer fires (timer coarseness plus scheduler delay), the in-flight body read fails first, and both body-read error sites map the failure straight to internal:

  • client/mod.rs:2042-2046 (failed to read response body)
  • client/mod.rs:2662-2666 (error reading response body)

The codebase already handles the equivalent race on the trailer path: when grpc-status is missing and the deadline has elapsed, the synthesized error is upgraded to deadline_exceeded (client/mod.rs:2133-2146), with a comment citing the gRPC spec behavior of grpc-go and connect-go (RST_STREAM CANCEL is upgraded to DEADLINE_EXCEEDED after deadline elapse; connect-go checks ctx.Err() before classifying transport errors).

The fix is to apply the same upgrade at the body-read error sites: if a deadline was set and has elapsed when a transport read error surfaces, classify it as deadline_exceeded instead of internal. This would also make the conformance suite stable on jittery hosts.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions