Skip to content

codex exec: multi_agent_v2 subagent results unusable — parent turn fails with "Encrypted function output content could not be decrypted or decoded" #33267

Open

Description

@blakegallagher1

Environment

  • codex-cli 0.144.4 (current latest release), npm install @openai/codex, darwin-arm64
  • macOS 27.0 (Apple Silicon)
  • Auth: ChatGPT (Pro plan), credentials in keyring (cli_auth_credentials_store = "keyring")
  • Model: gpt-5.6-sol, reasoning effort medium

Minimal configuration

[features.multi_agent_v2]
enabled = true
max_concurrent_threads_per_session = 1000

(Also reproduces with the field left at its default; and with features.enable_request_compression=false,
features.concurrent_reasoning_summaries=false, service_tier="auto" — none of these affect it.)

Minimal command

codex exec --skip-git-repo-check \
  "Using agents__spawn_agent, spawn exactly 1 subagent whose sole task is: reply with the word OK. \
   Wait for it with agents__wait_agent. Reply exactly: SPAWNED=<0|1> ERRORS=<none|exact text>."

Expected behavior

The child spawns, completes, and its output is returned to the parent; the parent reports SPAWNED=1 ERRORS=none.

Actual behavior

The child spawns and completes (spawn/limiter layer works; no AgentLimitReached even at 8 concurrent children),
but the parent cannot read the child's output. Every run ends with:

stream disconnected before completion: Encrypted function output content could not be decrypted or decoded.

RUST_LOG=error,codex_core=info places the failure in the parent turn while consuming inter-agent output:

INFO session_loop{thread_id=<uuid>}:submission_dispatch{otel.name="op.dispatch.inter_agent_communication" ...}
  :turn{... model=gpt-5.6-sol codex.turn.reasoning_effort=medium}: codex_core::session::turn:
  Turn error: stream disconnected before completion: Encrypted function output content could not be decrypted or decoded.

Reproduction rate

9/9 across: child counts 1 and 8; agent types default and a custom TOML role; root models
gpt-5.6-sol AND gpt-5.6-terra; fork_turns:"all" AND fork_turns:"none"; compression/summary
feature toggles on and off; service_tier priority and auto. 100% in codex exec (non-interactive).

Diagnostic narrowing (things ruled out)

  • Server-originated error: the string "could not be decrypted or decoded" does not exist in the
    0.144.4 client binary — only the stream disconnected before completion: wrapper is client-side.
    The server rejects the FunctionCallOutputBody.encrypted_content the client submits back.
  • Not model-gated at the root: identical failure with sol and terra roots.
  • Not forked-history contamination: fork_turns:"none" (clean child, no inherited encrypted
    items) fails identically — so the encrypted payload at fault is the agents-tool function output
    itself, not parent turns carried into the child (distinguishing this from Codex session replay can fail with invalid_encrypted_content from persisted encrypted reasoning/compaction records #25290's mechanism).
  • Children do spawn (rollout files are created per child under ~/.codex/sessions/), but in exec
    runs the child tasks did not observably execute tools (a child instructed to write a file via shell
    never created it), and agents__wait_agent sometimes returns "Wait completed" with no usable
    output — so a file-relay workaround is NOT viable either. Headless multi-agent is fully unusable.

Interactive comparison

Interactive TUI/Desktop multi-agent flows on the same machine/config are configured and in routine use;
this failure has only been observed via codex exec. (Not re-verified interactively at exactly 0.144.4 —
maintainers may want to confirm whether the encrypted-output path differs between exec and interactive.)

Possibly related

Impact

Scripted/CI multi-agent orchestration through codex exec cannot retrieve any subagent results,
which blocks headless use of multi_agent_v2 entirely.

Activity

  1. added
    bugSomething isn't working
    CLIIssues related to the Codex CLI
    execIssues related to the `codex exec` subcommand
    subagentIssues involving subagents or multi-agent features
    on Jul 15, 2026
  2. ignatremizov commented on Jul 16, 2026

    @ignatremizov

    Underlying issue might be #28058 - when they added encryption they didn't check all use of codex exec

    Current workaround to get multi agent v1 for gpt-5.6-sol (which does not have this issue) is to override models.json catalog (make a copy from source) and change multi_agent_version to null (so it's by config) or v1 (so it's by model catalog json), and disabling deferred tools search.

  3. romacv commented on Jul 22, 2026

    @romacv

    Confirming this on codex-cli 0.145.0-alpha.24, macOS 27.0 arm64, using interactive Codex collaboration. Four out of four custom reviewer spawns failed with the exact same error, including fork_turns: "none".

    Although multi_agent_v2.enabled = false in my config, the current model catalog forces gpt-5.6-terra to multi_agent_version: "v2". The child is created, but the parent cannot read its result. Regular parent tool calls continue working.

    This also confirms that disabling the config flag alone is not a sufficient workaround when the model catalog selects V2.

  4. jkenter0528 commented on Jul 24, 2026

    @jkenter0528

    Confirming this is also breaking interactive Codex Desktop on Windows, not only codex exec.

    Environment

    • Codex App: 26.721.3996.0
    • codex-cli: 0.145.0 (the failure was already observed before this install while the prior 0.144.5 runtime was active)
    • Windows: Microsoft Windows NT 10.0.26200.0 x64
    • Root model: gpt-5.6-sol, reasoning medium
    • Native MultiAgentV2 with model-routed custom agents and fork_turns: "none"

    Payload-level before/after from retained rollout JSONL

    • July 16, successful interactive v2 runs on the same root model: child-to-parent agent_message records contained input_text plus valid opaque encrypted_content beginning gAAAAA...; 0 malformed plaintext-in-encrypted blocks and 0 decrypt errors.
    • Current failing runs: child-to-parent records still label the second block encrypted_content, but the value is ordinary plaintext status/result prose rather than an encrypted token. Across the retained failing runs, 6 such malformed blocks were recorded and the parent produced the exact decrypt/decode error repeatedly.
    • Once a malformed record is stored, retrying the same Desktop thread fails immediately because the bad history is replayed.
    • Multiple fresh parent threads reproduced this after spawning three children, so this is not isolated thread corruption.

    codex doctor reports healthy state databases, auth, WebSocket, and endpoint reachability. The current remote model catalog forces both Sol and Terra to multi_agent_version: "v2", so setting features.multi_agent_v2.enabled = false alone is insufficient.

    The temporary local recovery was a startup-only model_catalog_json copy routing Sol/Terra to v1; effective routing verifies as v1 after the override. This restores work but removes the v2 workflow we rely on. The regression is a major blocker for visible, steerable Desktop subagents.

  5. JiaqiLiRonnie commented on Sep 4, 2026

    @JiaqiLiRonnie

    Additional interactive Desktop reproduction and recovery notes from a macOS/Apple Silicon case using Codex Desktop/app-server and multi_agent_v2:

    • Normalizing the provider metadata (state_5.sqlite.threads.model_provider plus every rollout session_meta.model_provider / model_provider_id) makes the route selectable, but it does not repair encrypted inter-agent payloads that already exist.
    • After a provider migration and a full restart, both the original parent and a fork still reproduced stream disconnected before completion: Encrypted function output content could not be decrypted or decoded. This supports the payload-level/upstream boundary described in this issue rather than a simple provider-name mismatch.
    • A fork is not necessarily clean: if it is based on the current paginated history, it can copy the bad history and fail again. fork_turns: none or an earlier completed-turn fork is a more meaningful isolation test.
    • A data-side salvage was possible in this case only by removing unreadable encrypted payloads while preserving visible messages, summaries, tool results, and project files. Rewriting rollout JSONL also requires updating paginated history byte offsets; otherwise the next failure becomes invalid paginated history lineage.

    Practical user guidance: do not assume that changing the provider or restarting will fix this error. Avoid the affected v2 multi-agent path; use v1 only if the current model catalog/config supports it, or continue in a clean thread with a plaintext checkpoint. Manual rollout editing should always be preceded by a backup.

  6. Yilmhi commented on Sep 19, 2026

    @Yilmhi

    Windows desktop + self-hosted Responses endpoint: sub-agents on GPT models fail every time, the same spawn on a non-GPT model succeeds

    Adding a reproduction that may narrow this down, plus one negative result.

    Environment

    • Codex Desktop on Windows 11, app 26.908.40834, CLI 0.154.0-alpha.6.2
    • model_provider is a local OpenAI-compatible Responses endpoint that fronts chatgpt.com/backend-api/codex with ChatGPT OAuth passthrough. The endpoint serves both DeepSeek and GPT models and routes by model name.
    • Root model deepseek/deepseek-flash
    • Model catalog: gpt-5.6-luna → multi_agent_version: "v1", gpt-5.6-terra → "v2"

    Reproduction

    Spawn a sub-agent on a GPT model (fork_turns: "none", model override gpt-5.6-luna) with a task that only asks it to reply with one word:

    Agent errored: stream disconnected before completion: Encrypted function output content could not be decrypted or decoded.
    
    • 3/3 spawns failed this way (two text-only tasks, one tool-using task). The child rollout contains the task agent_message and then no output items at all.
    • The same spawn on deepseek/deepseek-flash through the same endpoint succeeded 4/4, including a child that called tools and a child that spawned its own sub-agent.

    Payload observation (consistent with @jkenter0528's before/after)

    The child's task agent_message carries:

    {"type":"encrypted_content","encrypted_content":"只回一句话,内容是 banana。不要调用任何工具。"}

    readable plaintext where the successful payloads described above have opaque gAAAAA… ciphertext.

    Negative result: the wire shape alone does not reproduce it

    Replaying the request straight at the same endpoint (model gpt-5.6-luna, store: false, stream: true, author/recipient set on the item) returns 200 in all three of these variants:

    input result
    agent_message with a plaintext encrypted_content block 200
    same payload sent as input_text 200
    no payload block at all 200

    So a malformed plaintext-in-encrypted_content block in the request body is not sufficient by itself. The failure looks like it lives in how the client reads and re-encodes encrypted payloads, rather than in what the request body contains.

    The catalog workaround suggested in this thread does not help here: gpt-5.6-luna already reports multi_agent_version: "v1", and it still fails.

    Happy to run a build with extra tracing, or to test a patch, if that would help.

    Update — mechanism pinpoints to cross-provider replay, but a wire-level fix is not enough

    Cross-referencing #17541 ("Model switch mid-conversation fails: encrypted content could not be decrypted") and #15219: an encrypted payload only verifies for the provider/model that issued it, and replaying a foreign one makes the upstream reject the turn. In our setup the root model is a DeepSeek model served by the same endpoint, so every sub-agent spawn is a cross-provider model switch, which fits the 100% reproduction rate.

    Two concrete things we learned while testing a fix on the endpoint side (a local proxy that normalises the request before it reaches chatgpt.com/backend-api/codex):

    1. ChatGPT rejects a reasoning item that carries both encrypted_content and a non-empty content array:
      Invalid 'input[0].content': array too long. Expected an array with maximum length 0, but got an array with length 1 instead.
      So a replayed reasoning item must be either plaintext-only, or ciphertext-only with content: [].
    2. Dropping encrypted payloads the target did not issue (anything not gAAAAA…) and unwrapping locally-sealed compactions turns a previously failing body into a 200: the same request with a DeepSeek-issued reasoning token in history went 400 → 200 after the change.

    That fix does not resolve the sub-agent failure though. After it, 4/4 GPT-model children still end with:

    Agent errored: stream disconnected before completion: Encrypted function output content could not be decrypted or decoded.
    

    The child rollout holds the task agent_message and no output items at all, while the endpoint logs the corresponding GPT requests completing with 200 over HTTP and the client failing on the websocket transport. So whatever fails is on the client side of the encrypted payloads, not in the request body — consistent with the payload-level/upstream-boundary conclusion in the comments above.

    Happy to run a build with tracing around the decrypt path, or to test a patch.

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

    CLIIssues related to the Codex CLIbugSomething isn't workingexecIssues related to the `codex exec` subcommandsubagentIssues involving subagents or multi-agent features

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions