Skip to content

compaction: reasoning encrypted_content from the compaction agent is replayed into the main chain → permanently bricked session on Azure Foundry Responses #48942

Description

@witekjedrzejewski

Summary

Assistant messages with mode: "compaction" persist their reasoning parts including metadata.openai.reasoningEncryptedContent. Those parts are then replayed in every subsequent request on the main chain.

The compaction turn is a separate, uncached one-off call (tokens.cache.read: 0), and its encrypted reasoning blobs are bound to a different continuation identity than every other response in the session. Azure Foundry's Responses endpoint rejects the mixed input array:

HTTP 400  invalid_request_error  param: input  code: invalid_value
Conflicting authenticated continuation identities.

The error is isRetryable: false, so the session is permanently dead: every prompt fails in ~5s. /compact cannot rescue it either, because the compaction request itself replays the poisoned items.

Environment

  • opencode: 1.18.30 (session originally created under 1.18.20)
  • OS: macOS 26.6.2, arm64
  • Install: Homebrew
  • Provider: custom openai-foundry, npm: @ai-sdk/openai, Azure Foundry Responses endpoint behind an internal gateway (/openai/v1/responses)
  • Model: gpt-5.6-sol, variant xhigh — same model/provider/variant for the whole session, no model switching

Reproduction

  1. Run a long session against an Azure Foundry Responses-API provider.
  2. Let auto-compaction fire. It produces an assistant message with mode: "compaction", agent: "compaction", summary: true, carrying both a text part (the summary) and several reasoning parts with reasoningEncryptedContent.
  3. Continue the session past the compaction point.
  4. Every subsequent request replays the compaction message's reasoning items alongside the main chain's → 400 Conflicting authenticated continuation identities.

In my case the compaction fired on 09-09; the endpoint began enforcing the identity check around 09-10 08:00 UTC, and the session died at that point with no user-visible cause.

Evidence

I extracted the stored reasoning items from the affected session and replayed them directly against the endpoint. The input array held the post-compaction reasoning items plus a trivial "say ok" user message.

input result
all 581 post-compaction items CONFLICT (3/3 runs)
same 581 minus the compaction message's 3 items OK (3/3 runs)
the compaction message's 3 items alone OK
any one compaction item + any one later item CONFLICT
one pre-compaction item + one latest item OK

Binary search over the prefix converged on the first post-compaction non-compaction item as the first to collide — i.e. the compaction message's items are incompatible with everything that follows, and self-consistent among themselves.

Deleting just those 3 reasoning parts via DELETE /session/{id}/message/{id}/part/{id}, leaving the 4212-char summary text part intact, makes the full stored history replay cleanly. Confirmed end-to-end: after the deletion the session resumed and streams normally, with no loss of context.

A second session on the same machine corroborates the mechanism: it died on 09-10 08:17 from its 09-09 compaction message, then a new compaction on 09-10 11:30 pushed the poisoned item out of the replay window and it resumed working. It now carries 2 fresh encrypted reasoning parts on the new compaction message — the same latent failure.

Suggested fix

1. Don't persist encrypted reasoning on compaction messages. Only the summary text is ever needed from a mode: "compaction" turn. Dropping reasoningEncryptedContent / itemId for those messages removes the root cause and costs nothing.

2. Add this error to the stale-reasoning classifier. The open PRs #48908 and #48918 add a recovery path (strip crypto tokens, retry once) keyed on:

  • encrypted_content was not issued to this caller
  • invalid_encrypted_content
  • Referenced reasoning item '...' was not found or has expired

Conflicting authenticated continuation identities. is a distinct Azure-side string and would not be matched, so those PRs leave this case bricked. It has the same shape (400 / invalid_request_error / param: input) and the same remedy.

Fix 1 alone resolves this report. Fix 2 is worth having regardless, since it also covers identity divergence from any other source.

Related

Same family: caller-bound reasoning state persisted and replayed. This one is distinguished by the poisoned item being generated by opencode's own compaction agent rather than by an external change (restart, idle, model switch), which is why it is both reproducible and permanent.

Workaround

Delete the reasoning parts on the compaction message, keeping its text part:

DELETE /session/{sessionID}/message/{compactionMessageID}/part/{reasoningPartID}

Gateway hostname and request IDs redacted; happy to supply Azure apim-request-id / x-request-id values privately for upstream triage.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions