openclaw - ✅(Solved) Fix [Bug]: github-copilot / gpt-5.4 intermittently fails with `401 input item ID does not belong to this connection` across sessions/agents [1 pull requests, 1 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#66424Fetched 2026-04-15 06:26:12
View on GitHub
Comments
0
Participants
1
Timeline
3
Reactions
0
Participants
Timeline (top)
labeled ×2cross-referenced ×1

OpenClaw intermittently fails on provider=github-copilot / model=gpt-5.4 with:

401 input item ID does not belong to this connection

The session gets stuck — every subsequent message returns the same error until the user runs /new.

Error Message

The session gets stuck — every subsequent message returns the same error until the user runs /new. after a few messages the error appears

  • classify the error correctly as replay_invalid
  1. Only if retry also fails, surface the error to the user The error text "401 input item ID does not belong to this connection" hits the classification pipeline: The error text "401 input item ID does not belong to this connection" hits the classification pipeline:
  2. formatAssistantErrorText() has no handler for "unknown" in this case → passes the raw error string through verbatim. This is semantically the same class of error: the provider is rejecting an item reference from a prior conversation/connection. It should be classified as replay_invalid. Even when an error IS classified as replay_invalid, the current behavior is just to display:
  • Token was freshly renewed and valid when the error occurred
  • The error text explicitly says "connection", not token/scope/auth

Root Cause

OpenClaw intermittently fails on provider=github-copilot / model=gpt-5.4 with:

401 input item ID does not belong to this connection

The session gets stuck — every subsequent message returns the same error until the user runs /new.

Fix Action

Fixed

PR fix notes

PR #66475: fix(agents): classify connection-mismatch replay errors as replay-invalid

Description (problem / solution / changelog)

Summary\n\nClassify the exact provider/runtime wording 401 input item ID does not belong to this connection as replay_invalid, so it follows the existing session-reset guidance instead of falling through to a raw 401-style failure.\n\nCloses #66424.\n\n## What changed\n- broadened the replay-invalid matcher in src/agents/pi-embedded-helpers/errors.ts\n- added a classifier regression for the exact connection-mismatch wording\n- added a formatter regression to prove the user-facing /new hint still appears\n\n## Validation\n- ./node_modules/.bin/vitest run src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts src/agents/pi-embedded-helpers.formatassistanterrortext.test.ts\n\n## Evidence\n- evidence/github-copilot-connection-replay-invalid/\n\n## AI-assisted\n- yes\n

Changed files

  • src/agents/pi-embedded-helpers.formatassistanterrortext.test.ts (modified, +6/-0)
  • src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts (modified, +3/-0)
  • src/agents/pi-embedded-helpers/errors.ts (modified, +1/-1)

Code Example

401 input item ID does not belong to this connection

---

/\bprevious_response_id\b.*\b(?:invalid|unknown|not found|does not exist|expired|mismatch)\b|...

---

if (status === 401 || status === 403) {
       if (message && isAuthPermanentErrorMessage(message)) return "auth_permanent";
       if (messageReason === "billing") return "billing";
       return "auth";   // ← lands here
   }

---

**File:** `src/agents/pi-embedded-helpers.ts` (minified as `pi-embedded-helpers-*.js`)

The error text `"401 input item ID does not belong to this connection"` hits the classification pipeline:

1. `classifyProviderRuntimeFailureKind()` is called
2. It calls `isReplayInvalidErrorMessage()` → checks `REPLAY_INVALID_RE`:
   
   /\bprevious_response_id\b.*\b(?:invalid|unknown|not found|does not exist|expired|mismatch)\b|...
   
   This regex only matches `previous_response_id` + specific keywords.
   **It does NOT match `"input item ID does not belong to this connection"`** → returns `false`.

3. Then `classifyFailoverSignal()` is called → sees HTTP status 401 → calls `classifyFailoverClassificationFromHttpStatus(401, ...)`:
   
   if (status === 401 || status === 403) {
       if (message && isAuthPermanentErrorMessage(message)) return "auth_permanent";
       if (messageReason === "billing") return "billing";
       return "auth";   // ← lands here
   }
   

4. But `classifyProviderRuntimeFailureKind` doesn't have an explicit return for `"auth"` → falls through to `return "unknown"`.

5. `formatAssistantErrorText()` has no handler for `"unknown"` in this case → passes the raw error string through verbatim.

**Result:** No recovery, no chain-drop, no retry. The session stays stuck.

### 2. The `REPLAY_INVALID_RE` regex is too narrow

The regex recognizes these patterns:
- `previous_response_id` + invalid/unknown/not found/expired/mismatch
- `tool_use.input` / `tool_call.arguments` + missing/required
- `incorrect role information`
- `roles must alternate`

But does **not** recognize:
- `input item ID does not belong to this connection`

This is semantically the **same class of error**: the provider is rejecting an item reference from a prior conversation/connection. It should be classified as `replay_invalid`.

### 3. No automatic recovery for stale conversation state

Even when an error IS classified as `replay_invalid`, the current behavior is just to display:

"Session history or replay state is invalid. Use /new to start a fresh session and try again."


There is no automatic retry with a dropped response chain. The user must manually `/new`.
RAW_BUFFERClick to expand / collapse

Bug type

Regression (worked before, now fails)

Beta release blocker

No

Summary

OpenClaw intermittently fails on provider=github-copilot / model=gpt-5.4 with:

401 input item ID does not belong to this connection

The session gets stuck — every subsequent message returns the same error until the user runs /new.

Steps to reproduce

after upgrading last week it started to occurs having 4 agents on different channels using github-copilot provider after a few messages the error appears

Expected behavior

  • classify the error correctly as replay_invalid
  • surface a meaningful user message: "Session history or replay state is invalid. Use /new..."
  • instead of silently repeating the raw 401

Better (automatic retry with chain drop)

When replay_invalid is detected:

  1. Drop the previous_response_id / response chain linkage for this session
  2. Retry the current turn as a fresh provider request
  3. Only if retry also fails, surface the error to the user

This would eliminate the need for manual /new in most cases.

Actual behavior

1. Misclassification: treated as generic auth instead of replay_invalid

File: src/agents/pi-embedded-helpers.ts (minified as pi-embedded-helpers-*.js)

The error text "401 input item ID does not belong to this connection" hits the classification pipeline:

  1. classifyProviderRuntimeFailureKind() is called

  2. It calls isReplayInvalidErrorMessage() → checks REPLAY_INVALID_RE:

    /\bprevious_response_id\b.*\b(?:invalid|unknown|not found|does not exist|expired|mismatch)\b|...

    This regex only matches previous_response_id + specific keywords. It does NOT match "input item ID does not belong to this connection" → returns false.

  3. Then classifyFailoverSignal() is called → sees HTTP status 401 → calls classifyFailoverClassificationFromHttpStatus(401, ...):

    if (status === 401 || status === 403) {
        if (message && isAuthPermanentErrorMessage(message)) return "auth_permanent";
        if (messageReason === "billing") return "billing";
        return "auth";   // ← lands here
    }
  4. But classifyProviderRuntimeFailureKind doesn't have an explicit return for "auth" → falls through to return "unknown".

OpenClaw version

2026.4.12

Operating system

Linux (x64) Ubuntu 24.04

Install method

No response

Model

github-copilot/gpt-5.4

Provider / routing chain

github-copilot

Additional provider/model setup details

No response

Logs, screenshots, and evidence

**File:** `src/agents/pi-embedded-helpers.ts` (minified as `pi-embedded-helpers-*.js`)

The error text `"401 input item ID does not belong to this connection"` hits the classification pipeline:

1. `classifyProviderRuntimeFailureKind()` is called
2. It calls `isReplayInvalidErrorMessage()` → checks `REPLAY_INVALID_RE`:
   
   /\bprevious_response_id\b.*\b(?:invalid|unknown|not found|does not exist|expired|mismatch)\b|...
   
   This regex only matches `previous_response_id` + specific keywords.
   **It does NOT match `"input item ID does not belong to this connection"`** → returns `false`.

3. Then `classifyFailoverSignal()` is called → sees HTTP status 401 → calls `classifyFailoverClassificationFromHttpStatus(401, ...)`:
   
   if (status === 401 || status === 403) {
       if (message && isAuthPermanentErrorMessage(message)) return "auth_permanent";
       if (messageReason === "billing") return "billing";
       return "auth";   // ← lands here
   }
   

4. But `classifyProviderRuntimeFailureKind` doesn't have an explicit return for `"auth"` → falls through to `return "unknown"`.

5. `formatAssistantErrorText()` has no handler for `"unknown"` in this case → passes the raw error string through verbatim.

**Result:** No recovery, no chain-drop, no retry. The session stays stuck.

### 2. The `REPLAY_INVALID_RE` regex is too narrow

The regex recognizes these patterns:
- `previous_response_id` + invalid/unknown/not found/expired/mismatch
- `tool_use.input` / `tool_call.arguments` + missing/required
- `incorrect role information`
- `roles must alternate`

But does **not** recognize:
- `input item ID does not belong to this connection`

This is semantically the **same class of error**: the provider is rejecting an item reference from a prior conversation/connection. It should be classified as `replay_invalid`.

### 3. No automatic recovery for stale conversation state

Even when an error IS classified as `replay_invalid`, the current behavior is just to display:

"Session history or replay state is invalid. Use /new to start a fresh session and try again."


There is no automatic retry with a dropped response chain. The user must manually `/new`.

Impact and severity

No response

Additional information

  • Multiple dates, sessions, and agents
  • Always github-copilot / gpt-5.4 / openai-responses
  • /new resolves it (breaks the chain)
  • Token was freshly renewed and valid when the error occurred
  • The error text explicitly says "connection", not token/scope/auth
  • Multiple agents on the same gateway may increase the chance of hitting this (shared provider connection pool?)

extent analysis

TL;DR

Update the REPLAY_INVALID_RE regex to match the error message "input item ID does not belong to this connection" to correctly classify the error as replay_invalid.

Guidance

  • Update the REPLAY_INVALID_RE regex in src/agents/pi-embedded-helpers.ts to include the new error message pattern.
  • Add a handler for the replay_invalid error in formatAssistantErrorText() to surface a meaningful user message and drop the response chain.
  • Implement automatic retry with chain drop when replay_invalid is detected, as described in the "Better (automatic retry with chain drop)" section.
  • Verify that the updated regex correctly matches the error message and that the automatic retry mechanism works as expected.

Example

const REPLAY_INVALID_RE = /\bprevious_response_id\b.*\b(?:invalid|unknown|not found|does not exist|expired|mismatch)\b|input item ID does not belong to this connection|.../;

// In classifyProviderRuntimeFailureKind()
if (isReplayInvalidErrorMessage(message)) {
  return "replay_invalid";
}

// In formatAssistantErrorText()
if (errorKind === "replay_invalid") {
  return "Session history or replay state is invalid. Use /new to start a fresh session and try again.";
}

Notes

The current implementation only matches specific keywords related to previous_response_id, but the new error message "input item ID does not belong to this connection" is not recognized. Updating the regex to include this pattern should fix the misclassification issue. Additionally, implementing automatic retry with chain drop will improve the user experience by eliminating the need for manual /new commands.

Recommendation

Apply the workaround by updating the REPLAY_INVALID_RE regex and implementing automatic retry with chain drop, as this will correctly classify the error and provide a better 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

  • classify the error correctly as replay_invalid
  • surface a meaningful user message: "Session history or replay state is invalid. Use /new..."
  • instead of silently repeating the raw 401

Still need to ship something?

×6

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

Back to top recommendations

TRENDING