Skip to content

Codex App: text-log attachment can trigger “Request blocked” and poison subsequent turns #32177

Open

Description

@66Ton99

What version of the Codex App are you using (From “About Codex” dialog)?

26.707.31428

What subscription do you have?

ChatGPT Team

What platform is your computer?

Darwin 25.5.0 arm64 arm

What issue are you seeing?

In Codex App, attaching a plain-text application log to an established thread can cause the turn to fail after approximately 3–5 seconds with only:

Request blocked.

The failure is persistent within that thread. Sending a subsequent short message without any attachment also fails with the same generic error because the rejected attachment turn remains in the conversation history.

The affected turns complete without an assistant response. Local thread events show a completed task with no final assistant message. The desktop logs do not show an authentication, rate-limit, or HTTP 401/403/429 failure.

This reproduced with multiple different plain-text logs. The logs contained ordinary service diagnostics, model-loading messages, token counts, and request metadata. They did not contain credentials.

A control request in a new, short thread succeeds with the same account and model.

What steps can reproduce the bug?

  1. Open Codex App and use an established local-project thread with substantial completed history.
  2. Confirm that a normal turn still succeeds.
  3. Attach a plain-text service log. Reproduced attachment sizes ranged from approximately 42 KB / 425 lines to 115 KB / 1,094 lines.
  4. Ask Codex to inspect or summarize the log.
  5. Observe that the turn ends after approximately 3–5 seconds with Request blocked. and no assistant message.
  6. Send a short follow-up without an attachment.
  7. Observe that the follow-up is also blocked because the rejected attachment turn remains in the thread history.
  8. Create a new thread in the same project and send a short prompt without carrying over the attachment. Observe that it succeeds.

Relevant diagnostics:

  • Model: gpt-5.6-sol, medium reasoning.
  • Last successful turn before the attachment used 160,985 input tokens with a reported 353,400-token context window.
  • Account usage was below 10%; no rate-limit-reached state was reported.
  • Directly resuming the affected thread through the bundled CLI reproduces ERROR: Request blocked., so this is not only a stale renderer banner.
  • Session identifiers are intentionally omitted for privacy, but can be supplied privately if maintainers provide a secure channel.

What is the expected behavior?

Codex App should do one of the following:

  1. Accept the attachment when the combined request fits the supported context and request limits.
  2. Proactively compact, truncate, or summarize the attachment/history before sending.
  3. Reject the attachment before creating the turn and display a specific actionable error, such as an attachment-size or request-size limit.

A failed attachment turn must not poison the thread. A subsequent message without the attachment should work, or the UI should provide a clear way to remove/rollback the rejected turn.

Additional information

  • Reproduced after a full app restart.
  • Clearing GUI caches and refreshing authentication did not change the behavior.
  • Authentication and ordinary requests remained functional.
  • No screenshots or raw logs are attached because they may contain private workspace information.
  • No absolute local paths are included in this report.

Activity

  1. added
    bugSomething isn't working
    appIssues related to the Codex desktop app
    contextIssues related to context management (including compaction)
    sessionIssues involving session (thread) management, resuming, forking, naming, archiving
    on Jul 10, 2026
  2. github-actions commented on Jul 10, 2026

    @github-actions
    Contributor
  3. 66Ton99 commented on Jul 10, 2026

    @66Ton99
    Author

    Additional sanitized reproduction:

    • The failure also occurs without attaching a new file to the failing turn.
    • A task was continued into a worktree from another Codex App task.
    • Earlier in the task, automatic compaction reduced an oversized context from more than 131,072 tokens to approximately 37,000 tokens, after which multiple turns succeeded.
    • A later successful diagnostic turn reported 52,695 prompt tokens, 62 output tokens, and finish_reason=stop.
    • The next user message contained only a short “continue” instruction.
    • That turn immediately failed with the same generic Request blocked. banner and no assistant response.

    This suggests that a text-log attachment is one way to trigger the issue, but the persistent failure is more generally tied to inherited/compacted thread state. It may share a root cause with #32028, while this issue additionally covers the thread becoming unusable for subsequent small prompts.

    No screenshot, session identifier, raw log, personal information, or local path is included in this comment.

  4. 66Ton99 commented on Jul 10, 2026

    @66Ton99
    Author

    Impact update:

    For sustained Codex App workflows, gpt-5.6-sol is currently effectively unusable for me because of this bug.

    Short prompts in new threads may work, but long-running tasks repeatedly reach the broken state where:

    • a small follow-up such as “continue” returns Request blocked.;
    • the affected thread cannot be recovered by retrying, restarting the app, or sending a new attachment-free prompt;
    • work must be moved to another thread, losing the accumulated conversational context;
    • the replacement thread can eventually enter the same blocked state again.

    This has reproduced across multiple tasks using gpt-5.6-sol, including a task that had already compacted successfully and remained well below the reported context-window limit. As a result, the model cannot currently be relied upon for long-running coding tasks in the app.

    This is a regression compared with gpt-5.5. In the same Codex App environment, account, and workflow, switching to gpt-5.5 works normally: tasks and follow-up prompts continue without the persistent Request blocked. failure. The same workflow becomes unusable with gpt-5.6-sol.

    The working gpt-5.5 control makes an account-wide authentication, usage-limit, or general connectivity problem less likely and points to a regression in the gpt-5.6-sol request/context path.

  5. ezoushen commented on Jul 11, 2026

    @ezoushen

    Same here, my workaround for this issue is switching back to GPT-5.5 and do the compact and then switch back to 5.6 for continuing the original works

  6. myleswortham commented on Jul 11, 2026

    @myleswortham

    Same, and I found @ezoushen's workaround works, but I agree, it makes things unreliable at best. I've had it happen after it was, presumably, thinking for 20 minutes and then in the middle of that, "Request blocked." Sure, I can compact it at that point and reset it to the tune of either waiting another 20 minutes or noticeably worse performance since it doesn't seem like the context from it's 20 minutes of work without output translated to anything in context.

  7. gnmpwr commented on Jul 12, 2026

    @gnmpwr

    Yep, same here. I tried to continue working this morning and caught this bug in one chat. Everything was fine in the evening. I got up in the morning and it's not OK anymore. I didn't do anything unusual. No big documents. I hope guys from OpenAI is aware of this and fix it soon.

  8. myleswortham commented on Jul 12, 2026

    @myleswortham

    So I can now successfully recreate this issue on command from a new chat with the same prompt. Again, brand new chat, single prompt, all ending in failure.

    Image Image Image Image

    and my last prompt on why it happens has been... filtered for profanity "Request blocked keeps happening literally every time I ask this question. I have zero idea why. 1 minute, 2 minute, 10 minutes, in the middle, blocked, why?" but here's the response:

    Image

    And that's also a fresh prompt. The conclusion at the end seems to be potentially telling?

  9. cuipengfei commented on Jul 12, 2026

    @cuipengfei

    Cross-referencing a related finding that may help isolate the trigger.

    In can1357/oh-my-pi#5184, we performed marker minimization against Copilot gpt-5.6-* and found that the specific text string <|channel|>analysis in the input payload is sufficient to trigger:

    {"error":{"message":"Request blocked.","code":"invalid_request_body"}}

    Model matrix (same payload, one-shot each):

    Model Result
    gpt-5-mini, gpt-5.3-codex, gpt-5.4, gpt-5.4-mini, gpt-5.5 200 OK
    gpt-5.6-luna, gpt-5.6-sol, gpt-5.6-terra 400 Request blocked

    Not blocked: <|channel|> alone, <|channel|>final, <|channel|>commentary, <|channel|>reasoning, <|channel|>thinking.

    This suggests the gpt-5.6-* backend has an input-side safety classifier that rejects requests containing specific Harmony/ChatML control-token combinations — not just output-side moderation.

    Your report of compacted thread state triggering Request blocked could share this root cause: if the compacted/serialized context contains Harmony analysis-channel markers, those markers would be present in the input payload. It may be worth testing whether your failing threads contain <|channel|>analysis or similar control-token text.

    Additional note: @myleswortham reported being able to recreate this from a new chat with a single prompt (3/3), which suggests the trigger may not require long compacted history — certain prompt content alone may suffice. If you can share the reproducing prompt, we could test whether it contains control-token-like text patterns.

    Related: #32533, #32028.

  10. wiketool commented on Jul 14, 2026

    @wiketool

    same, thread id: 019f5fb6-069e-7b21-bb28-d9db3ca8f5f1

  11. rashmibanthia commented on Jul 20, 2026

    @rashmibanthia

    I hit this 12 times over 8 days for GPT 5.6 models. Root cause matches mentioned above

    My project stores GPT-OSS transcripts which includes harmony format, so source files contain <|channel|>analysis tokens. If Codex reads one of those files into context on gpt-5.6-sol and gpt-5.6-terra, the request is blocked. The same files work normally on gpt-5.5.

  12. bprashanth commented on Jul 22, 2026

    @bprashanth

    Codex CLI: 0.144.1
    Authentication: ChatGPT OAuth
    Time: 2026-07-22 13:58:50–14:03:32 UTC
    Rollout size: 48,696,373 bytes / 27,489 events
    Context compactions: 31

    Immediately before the failure, the thread emitted context_compacted.
    The next backend request returned HTTP 200, then the stream ended with:
    Turn error: Request blocked.

    Quota headers reported x-codex-primary-used-percent: 10.
    No authentication, sandbox, approval, or transport error occurred.

    Subsequent harmless messages in the same thread were also blocked.
    Changing model/reasoning settings did not recover the thread.
    A new thread on the same account and system succeeded immediately.

    The final retry additionally logged:
    incremental request failed, items didn't match
    unhandled responses event: error

    The CLI does not retain or display the backend error category/reason, making
    it impossible to distinguish moderation false positive from corrupted
    compacted/incremental conversation state.

  13. benvanik commented on Jul 31, 2026

    @benvanik

    I believe I just hit this too. My agent was reading the llama.cpp benchmarking corpus and beads that may have contained references to it, and then the entire session got poisoned (no recovery after rewind/resume):
    Image

    I suspect it hit various sequences that may have looked like prompt injection to a classifier. An analysis reports "Two later rewinds merely appended rollback markers (num_turns: 2, then 5). They did not remove the poisoned records." which would explain why it's still blocked even after rewinding.

    The results of this command are what triggered the poison:

      rg -n '<56-character search expression>' \
        /home/ben/src/llama.cpp/examples/llama-bench \
        /home/ben/src/llama.cpp/common \
        --glob '<6-character glob>' \
        --glob '*.cpp' \
        --glob '*.h' |
      head -240
    

    So, uh, if you work on llama.cpp beware.

    For those who hit this and need to restore a session, here's a workaround:


    I recovered a poisoned thread without editing SQLite or modifying the original rollout. This worked with codex-cli 0.144.0.

    1. Locate the rollout by session UUID under ~/.codex/sessions/**/rollout-*<SESSION_ID>.jsonl, then checksum/back it up.

    2. Have the recovery agent inspect only JSON structure—line number, record type, role, and byte length. Do not print or attach suspicious message/tool-output contents, or the recovery thread may also be blocked.

    3. Find the last known-good model-visible boundary, ideally a response_item assistant message. Copy the complete JSONL prefix through that line into /tmp/safe-prefix.jsonl. Leave the original untouched.

    4. Use Codex’s app-server to fork that shadow prefix. Initialize with the experimental API capability, then call:

    {"method":"initialize","id":0,"params":{"clientInfo":{"name":"codex_recovery","title":"Codex recovery","version":"1"},"capabilities":{"experimentalApi":true}}}
    {"method":"initialized","params":{}}
    {"method":"thread/fork","id":1,"params":{"threadId":"<ORIGINAL_SESSION_ID>","path":"/tmp/safe-prefix.jsonl"}}

    Feed those as JSONL to:

    codex app-server --listen stdio://

    The path parameter lets Codex fork the sanitized prefix into a fresh thread. If the prefix ends mid-turn, Codex adds its canonical interruption marker and turn_aborted event. It also creates the correct rollout and SQLite metadata, so manual database edits are unnecessary.

    I first tested this using an isolated temporary CODEX_HOME. After structural validation, I repeated the fork against the normal Codex home and used the returned thread ID.

    Finally, smoke-test the recovered thread with a prompt that forbids tools and any suspected source material:

    codex exec resume --json <NEW_THREAD_ID> \
      'Recovery smoke test. Do not inspect the suspected files or call tools. Reply with exactly RECOVERED.'

    Mine completed successfully and returned RECOVERED. The original poisoned rollout remained byte-for-byte unchanged.

    One wrinkle: normal thread/fork(lastTurnId=...) did not work after UI rewinds because the rollback markers had removed the desired turn from Codex’s effective turn projection. Forking a physical JSONL prefix via path avoided that problem.

  14. SilentBless commented on Aug 1, 2026

    @SilentBless

    got same, thread id: 019fba89-4f96-7f73-be24-532917e0ca4b

  15. frisco-deng commented on Aug 6, 2026

    @frisco-deng

    I have gotten the same issue on a main thread attempting remote operation and any thread attempting to continue off that previous thread (a total of 5 now).
    This is the same failure class as openai/codex #32533

    Image
  16. mrinmoyghosal commented on Aug 8, 2026

    @mrinmoyghosal

    same here, its terrible! So the workaround works for me one time is to copy the old session ID after quitting the session. And then ask codex to resume from that ID via prompt. if you run the codex resume .... command then it doesn't work for me and I get same "Request blocked" but with fresh session with prompting previous id somehow worked.

  17. shipiyouniao commented on Aug 11, 2026

    @shipiyouniao

    @jif-oai, tagging you because you appear to maintain the affected session/context paths; please redirect me if someone else owns this area.

    Reproduction

    I reproduced this in a fresh Codex task, so a long pre-existing conversation is not required:

    1. Opening Codex App: text-log attachment can trigger “Request blocked” and poison subsequent turns #32177 itself returned normally.
    2. Reading its comments returned normally.
    3. A broader related-issue search added a roughly 35k-character public tool result.
    4. The next model sampling request returned Request blocked.

    A second fresh task fetched the same issue set through gh api and exposed only bounded structured metadata; it completed successfully. This suggests that some tool-output content or combinations can trigger the service safeguard. Long sessions amplify the problem, but are not the only trigger.

    Client-side root cause

    The initial safeguard decision appears to be service-side. The client bug is what happens afterward: the rejected turn's user input, tool outputs, and partial model output remain model-visible and are resent on every later prompt, permanently poisoning the conversation.

    A rejected sampling request should behave like an uncommitted model-context transaction:

    • preserve the transcript and error in the rollout for UI and diagnostics;
    • exclude the rejected turn from later model-visible history;
    • apply the same rule during resume/fork reconstruction;
    • recognize legacy rollouts recorded as Other plus the exact Request blocked. message.

    Prototype

    I implemented that behavior in this commit:
    shipiyouniao@d0d4f1d

    It includes:

    • structured mapping for non-retryable invalid model requests;
    • live context rollback after rejection;
    • rollout reconstruction support, including the legacy encoding;
    • a mocked Responses API regression test proving that a rejected first prompt is not resent with the next successful prompt.

    The relevant protocol, reconstruction, and mocked Responses API tests pass locally.

    Related reports and scope

    This directly targets the session-poisoning behavior in #32177. It may also mitigate the permanently-unusable-session symptom in #31820, #32028, and #32533, but those reports have distinct image-limit or compaction triggers. #33103 looks like an initial safeguard false positive: this prototype preserves session usability after rejection, but does not alter or bypass the safeguard itself.

    External PRs are invitation-only, so I am sharing the analysis and prototype here first. If this approach matches the intended session semantics, I would be happy to open an invited PR or adjust the design before doing so.

  18. ooiuuii commented on Aug 13, 2026

    @ooiuuii

    I can reproduce the cross-task poisoning behavior on Codex desktop for Windows 26.803.10989.0.

    This is not just a single long task becoming non-resumable. A fresh investigation task worked normally for multiple turns, then consumed material from affected task histories while gathering diagnostics. That investigation task subsequently failed with the same generic error, and its immediate retry failed again:

    • task 019ffb57-cf5b-7a30-9b54-11700d96569c
    • failed turn 019ffb8a-2fa1-70d0-9ce4-5a0ebe5767a5: 308800 ms
    • immediate retry 019ffb8f-75bc-7a92-84ff-4e3a35335a0e: 4073 ms
    • both returned Request blocked. with codex_error_info: other
    • last recorded request: 62193 input tokens with a 258400 context window
    • weekly usage: 49%; rate_limit_reached_type=null

    I now have four affected tasks across an original long-running task, takeover/recovery tasks, and this evidence-building task:

    Task Last recorded input Confirmed blocked turns Fastest repeat failure
    019fb116-436b-7781-9dae-e1a8b8ad71de 104260 3 5934 ms
    019ffb28-4ac3-7981-90d5-009f0c55c6f5 175428 2 5883 ms
    019ffb51-d54d-77a2-8b95-8e67a6d1a2b3 88918 2 3275 ms
    019ffb57-cf5b-7a30-9b54-11700d96569c 62193 2 4073 ms

    Minimal follow-up prompts in affected tasks do not recover them. All four remained below the 258400 context window and none recorded rate_limit_reached_type. The Windows desktop log exposes only the local App Server turn/start IPC request ID; it does not expose a backend request ID, HTTP status, or rejection category.

    The evidence is consistent with this issue and also overlaps #33973 and #35160. I am intentionally not attaching raw rollout JSONL because it contains private project content and may contain the material that triggers the rejection. I can provide maintainers with a redacted allowlist extraction containing timestamps, task/turn IDs, token counts, context window, rate-limit state, durations, and hashes.

    Two recovery features would materially reduce impact even before the underlying rejection is fixed:

    1. expose a stable backend rejection category and request ID instead of only other;
    2. allow a safe fork/rollback from the last good turn without resending the rejected tail or raw tool output.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    appIssues related to the Codex desktop appbugSomething isn't workingcontextIssues related to context management (including compaction)sessionIssues involving session (thread) management, resuming, forking, naming, archiving

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions