Skip to content

maxTotalTimeout is never enforced unless a progress notification arrives #2695

Description

@sainikhiljuluri

What happens

maxTotalTimeout is documented as a hard cap:

Maximum total time (in milliseconds) to wait for a response. If exceeded, an SdkError with code SdkErrorCode.RequestTimeout will be raised, regardless of progress notifications.

It is not enforced unless a progress notification arrives and resetTimeoutOnProgress is set. Without both, the budget does nothing.

Measured on main, with a transport that never responds:

{ timeout: 1000, maxTotalTimeout: 150 }
  at 200ms  → still pending          (cap already exceeded)
  at 1200ms → "Request timed out"    (fired on `timeout`, not the cap)

{ maxTotalTimeout: 400 }
  after 3000ms → still pending       (waits for the 60s default timeout)

So a caller asking for a 150ms ceiling got 1000ms, and a caller asking for 400ms got 60s.

Why it happens

In packages/core-internal/src/shared/protocol.ts, _setupTimeout arms the pending timer with timeout only:

timeoutId: setTimeout(onTimeout, timeout),

maxTotalTimeout is read in exactly one place — the elapsed check inside _resetTimeout — and _resetTimeout has a single caller, guarded by:

if (timeoutInfo && responseHandler && timeoutInfo.resetTimeoutOnProgress) {

So the only way the budget is ever consulted is the progress path. A request with no progress notifications, or with resetTimeoutOnProgress left at its default of false, never checks it.

Why it survived

The existing test (test/shared/protocol.test.ts, "should respect maxTotalTimeout") passes resetTimeoutOnProgress: true and feeds two progress notifications, so it exercises the one path that works.

Expected

The pending timer should be armed for whichever limit comes first, and re-armed against the remaining budget on each progress notification, so the cap holds whether or not progress arrives.

Environment

main at 3924de99 (2.0.0-alpha.0). The same shape is present on v1.x.

Not related to #2224, #2136, #1870 or #2082 — those concern resetTimeoutOnProgress needing an onprogress callback, and none of them touch _setupTimeout or the arming.

I have a fix and tests ready and am happy to open a PR if useful.


AI assistance was used to investigate and write this report.

Metadata

Metadata

Assignees

No one assigned

    Labels

    v1Issues / PRs related to v1.xv2Ideas, requests and plans for v2 of the SDK which will incorporate major changes and fixes

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions