openclaw - 💡(How to fix) Fix [Bug]: HTTP 429 from GitHub Copilot is still misclassified as idle timeout on 2026.4.27 [2 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#75332Fetched 2026-05-01 05:35:03
View on GitHub
Comments
2
Participants
2
Timeline
4
Reactions
2
Author
Timeline (top)
commented ×2closed ×1cross-referenced ×1

GitHub Copilot /responses returns HTTP 429 for an exhausted weekly quota in under 1 second, but OpenClaw 2026.4.27 still does not surface the provider HTTP error promptly.

Instead, the model stream produces no assistant tokens and is eventually terminated by the LLM idle watchdog after the full default idle timeout:

LLM idle timeout (120s): no response from model

The run is tagged as timedOut: true and idleTimedOut: true, then the harness automatically retries the same prompt once. The second attempt also waits 120 seconds. End-to-end, the user sees roughly 4 minutes of latency for an upstream HTTP 429 that is available immediately.

This appears related to the previously fixed #71120, but the current symptom is different:

  • #71120: 429 caused a 10-minute silent hang on 2026.4.22.
  • This issue: 429 is misclassified as idleTimedOut twice on 2026.4.27.

Error Message

GitHub Copilot /responses returns HTTP 429 for an exhausted weekly quota in under 1 second, but OpenClaw 2026.4.27 still does not surface the provider HTTP error promptly.

  • The trajectory should preserve the HTTP status and provider error body, for example as model.failed or an equivalent provider/protocol error. The duplicated promptError string suggests the idle-timeout error may also be concatenated across an internal retry or bookkeeping layer.
  • An immediate upstream provider error is reported as timedOut + idleTimedOut, which is misleading during debugging.
  1. The streaming layer returns an async stream object, but its iterator neither yields nor throws the provider HTTP error.
  2. streamWithIdleTimeout has no HTTP status visibility, so it waits 120 seconds and throws the generic idle-timeout error. The minimum expected fix is for non-2xx provider responses to be converted into a typed provider/protocol error before the stream reaches the idle watchdog. HTTP status and body should be preserved in the trajectory, and 4xx responses should not be retried as idle timeouts.

Root Cause

GitHub Copilot /responses returns HTTP 429 for an exhausted weekly quota in under 1 second, but OpenClaw 2026.4.27 still does not surface the provider HTTP error promptly.

Instead, the model stream produces no assistant tokens and is eventually terminated by the LLM idle watchdog after the full default idle timeout:

LLM idle timeout (120s): no response from model

The run is tagged as timedOut: true and idleTimedOut: true, then the harness automatically retries the same prompt once. The second attempt also waits 120 seconds. End-to-end, the user sees roughly 4 minutes of latency for an upstream HTTP 429 that is available immediately.

This appears related to the previously fixed #71120, but the current symptom is different:

  • #71120: 429 caused a 10-minute silent hang on 2026.4.22.
  • This issue: 429 is misclassified as idleTimedOut twice on 2026.4.27.

Code Example

LLM idle timeout (120s): no response from model

---

{
  "aborted": true,
  "externalAbort": false,
  "timedOut": true,
  "idleTimedOut": true,
  "timedOutDuringCompaction": false,
  "promptError": "LLM idle timeout (120s): no response from model | LLM idle timeout (120s): no response from model",
  "promptErrorSource": "prompt",
  "assistantTexts": [],
  "provider": "github-copilot",
  "modelId": "gpt-5.4",
  "modelApi": "openai-responses"
}

---

curl -sS -N -o /tmp/out -w "HTTP %{http_code} total=%{time_total}s\n" \
  --max-time 15 \
  -H "Authorization: Bearer $TOK" \
  -H "Accept: text/event-stream" \
  -H "Content-Type: application/json" \
  -H "Copilot-Integration-Id: vscode-chat" \
  -H "Editor-Version: vscode/1.99.0" \
  -H "OpenAI-Intent: conversation-panel" \
  https://api.githubcopilot.com/responses \
  --data '{"model":"gpt-5.4","input":"ping","stream":true}'

---

HTTP 429 total=0.968s
Sorry, you've exceeded your weekly rate limit. Please review our [Terms of Service](https://docs.github.com/en/site-policy/github-terms/github-terms-of-service).

---

curl -sS -o /tmp/out -w "HTTP %{http_code} total=%{time_total}s\n" \
  --max-time 130 \
  -H "Authorization: Bearer $TOK" \
  -H "Content-Type: application/json" \
  -H "Copilot-Integration-Id: vscode-chat" \
  -H "Editor-Version: vscode/1.99.0" \
  -H "OpenAI-Intent: conversation-panel" \
  https://api.githubcopilot.com/chat/completions \
  --data '{"model":"gpt-5.4","messages":[{"role":"user","content":"ping"}],"stream":false}'

---

HTTP 429 total=0.856s
Sorry, you've exceeded your weekly rate limit. Please review our [Terms of Service](https://docs.github.com/en/site-policy/github-terms/github-terms-of-service).
RAW_BUFFERClick to expand / collapse

Bug type

Regression (or incomplete fix after #71120)

Beta release blocker

No

Summary

GitHub Copilot /responses returns HTTP 429 for an exhausted weekly quota in under 1 second, but OpenClaw 2026.4.27 still does not surface the provider HTTP error promptly.

Instead, the model stream produces no assistant tokens and is eventually terminated by the LLM idle watchdog after the full default idle timeout:

LLM idle timeout (120s): no response from model

The run is tagged as timedOut: true and idleTimedOut: true, then the harness automatically retries the same prompt once. The second attempt also waits 120 seconds. End-to-end, the user sees roughly 4 minutes of latency for an upstream HTTP 429 that is available immediately.

This appears related to the previously fixed #71120, but the current symptom is different:

  • #71120: 429 caused a 10-minute silent hang on 2026.4.22.
  • This issue: 429 is misclassified as idleTimedOut twice on 2026.4.27.

Steps to reproduce

  1. Use OpenClaw 2026.4.27 with GitHub Copilot as the provider and gpt-5.4 through the openai-responses API.
  2. Exhaust the Copilot weekly quota so that /responses returns HTTP 429.
  3. Send a simple inbound channel message to an agent using github-copilot/gpt-5.4.
  4. Observe the trajectory events and user-visible response timing.

Expected behavior

  • OpenClaw should detect the provider HTTP 429 within a few seconds.
  • The trajectory should preserve the HTTP status and provider error body, for example as model.failed or an equivalent provider/protocol error.
  • The run should not be classified as idleTimedOut.
  • 4xx provider errors, especially 429 quota exhaustion, should not be auto-retried as if the model produced no response.

Actual behavior

A single inbound Feishu message (om_x100b500b746598acb10a6bfe6f48cad, text 你好) produced two 120-second idle timeouts:

Time (UTC)Event
00:28:27Message arrives
00:28:34.653prompt.submitted for session 1
00:30:34.663model.completed, exactly 120.010s later
00:30:41.152prompt.submitted for session 2, same run retried
00:32:41.159model.completed, exactly 120.007s later

Both model.completed events include:

{
  "aborted": true,
  "externalAbort": false,
  "timedOut": true,
  "idleTimedOut": true,
  "timedOutDuringCompaction": false,
  "promptError": "LLM idle timeout (120s): no response from model | LLM idle timeout (120s): no response from model",
  "promptErrorSource": "prompt",
  "assistantTexts": [],
  "provider": "github-copilot",
  "modelId": "gpt-5.4",
  "modelApi": "openai-responses"
}

The duplicated promptError string suggests the idle-timeout error may also be concatenated across an internal retry or bookkeeping layer.

OpenClaw version

2026.4.27

Operating system

Ubuntu / Linux

Install method

npm/global install

Model

github-copilot/gpt-5.4

Provider / routing chain

github-copilot -> gpt-5.4 (openai-responses)

Additional provider/model setup details

The Copilot token itself was healthy:

  • GET /models returned HTTP 200 with 37 models in about 1 second.
  • The token had just been refreshed and had about 28 minutes until expiry.

Logs, screenshots, and evidence

Direct reproduction using the same cached Copilot token against the same endpoint the adapter uses:

curl -sS -N -o /tmp/out -w "HTTP %{http_code} total=%{time_total}s\n" \
  --max-time 15 \
  -H "Authorization: Bearer $TOK" \
  -H "Accept: text/event-stream" \
  -H "Content-Type: application/json" \
  -H "Copilot-Integration-Id: vscode-chat" \
  -H "Editor-Version: vscode/1.99.0" \
  -H "OpenAI-Intent: conversation-panel" \
  https://api.githubcopilot.com/responses \
  --data '{"model":"gpt-5.4","input":"ping","stream":true}'

Observed:

HTTP 429 total=0.968s
Sorry, you've exceeded your weekly rate limit. Please review our [Terms of Service](https://docs.github.com/en/site-policy/github-terms/github-terms-of-service).

For comparison, non-streaming chat completions also returns immediately:

curl -sS -o /tmp/out -w "HTTP %{http_code} total=%{time_total}s\n" \
  --max-time 130 \
  -H "Authorization: Bearer $TOK" \
  -H "Content-Type: application/json" \
  -H "Copilot-Integration-Id: vscode-chat" \
  -H "Editor-Version: vscode/1.99.0" \
  -H "OpenAI-Intent: conversation-panel" \
  https://api.githubcopilot.com/chat/completions \
  --data '{"model":"gpt-5.4","messages":[{"role":"user","content":"ping"}],"stream":false}'

Observed:

HTTP 429 total=0.856s
Sorry, you've exceeded your weekly rate limit. Please review our [Terms of Service](https://docs.github.com/en/site-policy/github-terms/github-terms-of-service).

The provider response is plain text, not SSE.

Impact and severity

  • An immediate upstream provider error is reported as timedOut + idleTimedOut, which is misleading during debugging.
  • User-visible latency becomes two full idle-timeout windows, roughly 4 minutes by default, instead of about 1 second.
  • Retrying an exhausted-quota 429 is counterproductive and may worsen rate-limit pressure.
  • The duplicated promptError makes the trajectory harder to interpret.

Additional information

Installed bundle pointers from the affected environment:

  • dist/selection-8xKkwZC_.js: streamWithIdleTimeout, resolveLlmIdleTimeoutMs, DEFAULT_LLM_IDLE_TIMEOUT_MS = 120_000.
  • dist/plugin-sdk/src/agents/pi-embedded-runner/run/llm-idle-timeout.d.ts: idle-timeout declarations.
  • dist/extensions/github-copilot/stream.js and dist/stream-B6dB0lb1.js: Copilot provider wrapper.

My reading of the failure mode is:

  1. The provider returns HTTP 429 with a non-SSE plain-text body.
  2. The streaming layer returns an async stream object, but its iterator neither yields nor throws the provider HTTP error.
  3. streamWithIdleTimeout has no HTTP status visibility, so it waits 120 seconds and throws the generic idle-timeout error.
  4. The retry layer treats this as a timeout and retries the same exhausted-quota call.

The minimum expected fix is for non-2xx provider responses to be converted into a typed provider/protocol error before the stream reaches the idle watchdog. HTTP status and body should be preserved in the trajectory, and 4xx responses should not be retried as idle timeouts.

extent analysis

TL;DR

The issue can be fixed by modifying the streaming layer to properly handle and propagate non-2xx provider responses, such as HTTP 429, to prevent them from being misclassified as idle timeouts.

Guidance

  • Modify the streamWithIdleTimeout function to check for non-2xx HTTP status codes in the provider response and throw a typed error that includes the HTTP status and body.
  • Ensure that the retry layer is updated to handle these typed errors and avoid retrying requests that have exceeded their quota.
  • Verify that the trajectory events include the correct HTTP status and provider error body for non-2xx responses.
  • Test the fix by reproducing the issue and checking that the user-visible latency is reduced and the error is properly reported.

Example

// Example of how to modify streamWithIdleTimeout to handle non-2xx responses
async function* streamWithIdleTimeout(stream, timeoutMs) {
  for await (const chunk of stream) {
    if (chunk.httpStatus && chunk.httpStatus >= 400) {
      throw new ProviderError(chunk.httpStatus, chunk.httpBody);
    }
    //...
  }
}

class ProviderError extends Error {
  constructor(httpStatus, httpBody) {
    super(`Provider error ${httpStatus}: ${httpBody}`);
    this.httpStatus = httpStatus;
    this.httpBody = httpBody;
  }
}

Notes

The provided example is a simplified illustration of how to handle non-2xx responses in the streaming layer. The actual implementation may vary depending on the specific requirements and constraints of the project.

Recommendation

Apply a workaround to modify the streaming layer to handle non-2xx provider responses, as this will allow for a more accurate and timely reporting of errors, reducing user-visible latency and improving the overall user experience.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

  • OpenClaw should detect the provider HTTP 429 within a few seconds.
  • The trajectory should preserve the HTTP status and provider error body, for example as model.failed or an equivalent provider/protocol error.
  • The run should not be classified as idleTimedOut.
  • 4xx provider errors, especially 429 quota exhaustion, should not be auto-retried as if the model produced no response.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix [Bug]: HTTP 429 from GitHub Copilot is still misclassified as idle timeout on 2026.4.27 [2 comments, 2 participants]