Skip to content

Copilot gpt-5.5: "input item ID does not belong to this connection" after switching auth token mid-session (stale Responses API itemId not invalidated) #31236

Description

@doomsday616

Description

When using the GitHub Copilot provider with gpt-5.5, the next gpt-5.5 turn in an existing session can fail with:

APIError 401: input item ID does not belong to this connection
url: https://api.githubcopilot.com/responses

This is deterministically reproducible whenever the active Copilot connection changes underneath the session — either because the stored Copilot credential was rotated (e.g. switching between multiple Copilot accounts when one runs out of quota), or because the session was used with a different model/provider in between and is then switched back to github-copilot/gpt-5.5. It has a clear root cause (details below). It is distinct from #26886, which reports the same error string but as a transient/random upstream disconnect with no reproduction steps. This report is the deterministic case caused by a Copilot Responses-API connection change.

Root cause

Copilot gpt-5.5 uses the stateful OpenAI Responses API (/responses), not stateless Chat Completions. Each assistant turn's reasoning and text parts persist an openai.itemId handle in part metadata. On the next turn, OpenCode references these prior itemIds as input items (server-side state reuse) instead of re-sending full history.

These itemIds are bound to the specific Copilot Responses-API connection that created them. If the active connection differs from the one that produced the stored itemIds — because the stored Copilot credential was swapped, or because intervening turns went through a different provider/model and the session then switches back — OpenCode still references the old itemIds, the new connection does not recognize them, and the server rejects the request with 401 input item ID does not belong to this connection.

Evidence from session storage (a stored part, values redacted):

{
  "type": "reasoning",
  "metadata": {
    "openai": {
      "itemId": "PFf6cBEQ……(long opaque per-connection handle, redacted)",
      "reasoningEncryptedContent": null
    }
  }
}

In affected sessions these itemId-bearing parts are not occasional: a single working session can accumulate well over a hundred parts (across reasoning, text, and tool types) each carrying an openai.itemId from the original connection. All of them become stale as soon as the active Copilot connection changes.

Why only Copilot gpt-5.5 is affected

  • Copilot claude-opus-4.8 (and other Claude models): use the Anthropic Messages format (stateless), never reference an itemId, so a connection change has no effect — continues fine.
  • OpenAI direct gpt-5.5: a separate provider/connection, does not reference Copilot's itemIds — continues fine.
  • Copilot gpt-5.5: references the stale Copilot itemIds — fails.

Note on how the active Copilot connection gets changed

Two paths produce a connection change under an existing session:

  1. Credential rotation. There is currently no first-class switch between multiple GitHub Copilot accounts (unlike the opencode.ai Console account, which has login / logout / switch). The Copilot auth plugin's authorize flow returns a single credential and writes it to the one fixed github-copilot key; re-running /connect overwrites the existing Copilot credential rather than adding a second account. So in practice the only way to rotate between Copilot accounts is to change the stored credential directly (editing auth.json, which on load is migrated into account.json and takes precedence while it exists).
  2. Switching to a different provider/model in the same session and then switching back to github-copilot/gpt-5.5. Intervening turns served by another provider/model (for example OpenAI-direct gpt-5.5) do not produce Copilot-recognised itemIds, but the session still holds the original Copilot itemIds in earlier parts. When github-copilot/gpt-5.5 resumes, those original itemIds are sent over what is now a different Copilot Responses-API connection and are rejected.

Either way the trigger to hook on is "the active Copilot Responses-API connection differs from the one that produced the cached itemIds", not a UI-level account-switch event (which does not exist for Copilot).

Workarounds tried

  • /compact does not fix it. The compaction record stored in the session is essentially a tail_start_id marker: it shifts where the model's new context window starts, but it does not delete or rewrite the earlier parts that hold openai.itemId metadata. Those stale itemIds remain in the session store and are still referenced by the next Copilot Responses-API request, so the 401 reproduces immediately after compaction.
  • Switching the session to github-copilot/claude-opus-4.8 or to OpenAI-direct gpt-5.5 works (no itemId reference). Switching back to github-copilot/gpt-5.5 immediately re-triggers the 401, which is the same root cause as the credential-rotation case.
  • The only consistently effective recovery today is starting a new session.

Suggested fix

When the active Copilot Responses-API connection changes (credential rotation, or resuming gpt-5.5 after intervening non-Copilot turns), invalidate / clear the cached Responses API itemId handles for affected sessions, including ones already persisted in parts. Alternatively (and more robustly), on receiving input item ID does not belong to this connection, automatically retry the request once without the stale itemId references, falling back to a full-history resend. The retry-on-error approach would make connection changes transparent for gpt-5.5 sessions and would also gracefully handle the transient/out-of-sync case in #26886.

Plugins

None

OpenCode version

First observed on 1.16.2; still reproducible on 1.17.3.

Steps to reproduce

Credential-rotation path:

  1. Authenticate the Copilot provider with token A.
  2. In a session, run several turns using github-copilot/gpt-5.5.
  3. Replace the Copilot credential with token B (a different Copilot account, identical models/quota) — e.g. by editing auth.json, since there is no multi-account switch for Copilot.
  4. In the same session, continue with github-copilot/gpt-5.5.
  5. Observe 401 input item ID does not belong to this connection.

Model/provider-switch path (no credential change required):

  1. In a session, run several turns using github-copilot/gpt-5.5 (accumulating itemId-bearing parts).
  2. In the same session, switch the model to a different provider/model (e.g. OpenAI-direct gpt-5.5, or another Copilot model) and run at least one turn.
  3. Switch the session back to github-copilot/gpt-5.5.
  4. Observe the same 401 input item ID does not belong to this connection.
  5. (Optional) Run /compact between steps 2 and 3 and confirm it does not prevent the failure — earlier itemId-bearing parts remain in the session store.

In both paths, switching the session to github-copilot/claude-opus-4.8 continues without error (Claude does not reference Copilot itemIds).

Screenshot and/or share link

No response

Operating System

Windows 11

Terminal

Windows Terminal

Related

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
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