`MultiAgentV2` `followup_task` accepts self-targets and can(and will) livelock orchestration

Open 💬 0 comments Opened Jul 17, 2026 by 0xdeafbeef

Summary

A MultiAgentV2 agent can call followup_task targeting its own canonical task path or thread ID.

The call succeeds and delivers a NEW_TASK whose author and recipient are the same agent. If the agent interprets this as delegation to another executor, it can repeatedly call wait_agent while waiting for itself to finish.

Reproduction

  1. Spawn a child named /root/self_followup_probe.
  2. From that child, call:

``json
{
"target": "/root/self_followup_probe",
"message": "Run
pwd and report the result."
}
``

  1. Observe that followup_task returns success.
  2. Observe a delivered NEW_TASK where both author and recipient are /root/self_followup_probe.

The same invalid call is accepted when targeting the caller by thread ID.

Expected behavior

followup_task should reject any target resolving to the calling thread and return a model-visible error before delivering the message.

Regression tests should cover self-targeting through:

  • the current canonical task path;
  • the current thread ID.

Impact

In my transcript, the agent delegated the task to itself and then waited for itself for 4 hours 14 minutes, issuing 239 wait_agent calls. The actual work never started. 😍

Source

followup_task rejects the root agent but does not check whether the resolved target is the calling thread:

https://github.com/openai/codex/blob/315195492c80fdade38e917c18f9584efd599304/codex-rs/core/src/tools/handlers/multi_agents_v2/message_tool.rs#L73-L88

interrupt_agent already performs the corresponding self-target check:

https://github.com/openai/codex/blob/315195492c80fdade38e917c18f9584efd599304/codex-rs/core/src/tools/handlers/multi_agents_v2/interrupt_agent.rs#L53-L57

The missing validation is:

receiver_thread_id == session.thread_id

Related but distinct

  • #32203 — completion routing for a non-child descendant;
  • #24951 — wait_agent exceeding its requested deadline;
  • #23296 — failure to execute an initial spawn task.

None covers followup_task targeting its own caller.

<details>
<summary>Definitely not a meme</summary>
<img width="1672" height="941" alt="Image" src="https://github.com/user-attachments/assets/218a4370-518c-47d8-9038-2af2ae09590e" />
</details>

View original on GitHub ↗