transfer_task is not concurrency-safe: parallel calls race on current-agent pointer, later calls fail with "No agents are configured in this list"
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 3.3k
- Forks
- 462
- Avg merge
- 1d 10h
- Merged PRs (30d)
- 273
Description
Symptom
When a model issues multiple transfer_task calls in one API response, Dispatcher.Process runs them in parallel goroutines (via concurrent.MapSlice). The first goroutine's swapCurrentAgent sets r.current to the target agent (e.g. "drafter"); subsequent goroutines' handleTaskTransfer → resolveSessionAgent read the mutated r.current, treat the target as the caller, and fail validation:
Agent drafter cannot transfer task to drafter: target agent not in sub-agents list. No agents are configured in this list.
Real-World Impact
Broke the docker-agent-action PR review pipeline on docker/frontends#16712:
- Evidence run: https://github.com/docker/frontends/actions/runs/33804270624
- First delegation succeeded; the other two failed due to the race
- The orchestrator issued all three
transfer_taskcalls in a single Anthropic API response (parallel tool use with a 3-chunk diff)
Root Cause
Concurrent mutation of r.current:
Thread 1 (call 1):
a = r.resolveSessionAgent(sess) → r.current = "orchestrator" → OK
validateAgentInList(orchestrator, "drafter") → PASS
runForwarding() → swapCurrentAgent: r.current = "drafter" ← mutated
Thread 2 (call 2, concurrent):
a = r.resolveSessionAgent(sess) → r.current = "drafter" ← reads mutated value
validateAgentInList(drafter, "drafter") → FAIL
The shared mutable field r.current is not safe for concurrent swapCurrentAgent + handleTaskTransfer calls. The caller agent identity must be captured before any concurrent dispatch, not re-read during validation.
Affected Versions
At least v1.120.0–v1.131.0. The parallel dispatch via concurrent.MapSlice (and hence the race) pre-exists v1.121.0; no fix found in v1.121.0..v1.131.0 history.
Suggested Fixes
- Store caller agent on session creation: Record the "owner agent" in the session object at creation time;
resolveSessionAgentreads the session-owned agent for root sessions, neverr.current. - Snapshot caller identity before dispatch: Capture the caller agent at the top of
handleTaskTransferbefore any concurrent dispatch; pass it through to validation (do not re-readr.current). - Serialize transfer_task in dispatcher: Add a mutex that serializes all
transfer_taskcalls; simplest runtime fix but less elegant.
Workaround
Set parallel_tool_calls: false on the model in your agent config. This prevents the model from returning multiple transfer_task calls in a single API response, eliminating the race entirely.
Key Code References
pkg/runtime/toolexec/dispatcher.go:257—concurrent.MapSlice(calls, ...)parallel dispatchpkg/runtime/agent_delegation.go:681—handleTaskTransferreadsr.currentviaresolveSessionAgentpkg/runtime/agent_delegation.go:326—runForwarding/swapCurrentAgentmutatesr.currentpkg/runtime/agent_router.go:76—ResolveSessionreadsr.currentfor unpinned sessions
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with pkg/runtime/toolexec/dispatcher.go:257 and trace the parallel calls into handleTaskTransfer at pkg/runtime/agent_delegation.go:681. Read runForwarding and swapCurrentAgent at agent_delegation.go:326, then inspect ResolveSession in agent_router.go:76. Reproduce the reported parallel transfer_task scenario and verify that concurrent calls retain the original caller identity without validation failures.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- backend, distributed-systems
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 54/100