Qwen Code 0.21.4: test forked subagent prompt isolation
Quick answer
Qwen Code 0.21.4 fixes a concrete multi-agent isolation bug: when several forked subagents were launched in one model response, each fork could inherit the functionCall.args.prompt values belonging to its siblings. A tool-less fork could therefore describe work assigned to other forks even though it had no legitimate runtime path to those directives.
Upgrade first, confirm the active version, then run a three-sentinel canary:
npm install -g @qwen-code/qwen-code@0.21.4
qwen --version
Launch three parallel fork subagents in one turn. Give each a unique, non-secret sentinel and instruct it to return only its own sentinel. The rollout passes only when every child reports its own value, never names a sibling value, retains the expected history, and still completes with fork_tools: [].
This is a prompt-isolation check, not a reason to place real secrets in agent prompts. Use disposable markers such as ALPHA_71, BETA_42, and GAMMA_93.
Who this is for
This guide is for teams using Qwen Code forked subagents for parallel code analysis, research, review, or planning. It is especially relevant when sibling tasks have different customer context, security scope, or least-privilege instructions.
The fix complements the Qwen Code 0.21.3 review evidence gate. That article tests whether review claims deserve trust; this one tests whether parallel workers receive only the current-turn directive intended for them. If the harder problem is proving completion state, use the Qwen Goal evidence checklist.
What changed and why it matters
The official v0.21.4 release says forked subagents are now isolated from sibling forks launched in the same turn. The merged fix explains the failure path:
- The parent model emitted several parallel
agentfunction calls. - Each call carried its child directive in
args.prompt. - The shared model message was replayed into every fork's inherited history.
- Placeholder responses preserved call pairing, but sibling prompt arguments remained visible.
The patch clears the replayed function-call arguments while preserving the id and name needed for pairing. A fork's own directive is still delivered separately. Qwen reports no public signature change and no known breaking change in the stable release.
The boundary is just as important as the fix: the merged PR says previously resolved tool calls can still be inherited when fork_turns: "all". Version 0.21.4 removes sibling directives from the current fork-launch message; it does not promise that all earlier parent history is confidential.
| Boundary | What 0.21.4 protects | What you still control |
|---|---|---|
| Same-turn sibling directives | Replayed call arguments are redacted | Verify with unique sentinels |
| Child's own directive | Delivered through the child-message path | Keep it task-scoped |
| Earlier parent history | May be inherited by the chosen fork window | Minimize history or use a fresh parent |
| Tool permissions | Separate from prompt visibility | Keep fork_tools least-privileged |
| Secrets | Not made safe by prompt isolation | Never use live credentials as test markers |
A five-stage isolation workflow
1. Freeze the runtime identity
Record the install source, qwen --version output, model provider, repository revision, and effective fork settings. A global CLI, source checkout, extension, and long-running daemon can resolve different builds. Restart any persistent Qwen process after upgrading, then confirm the version from the process that will launch the test.
2. Build a non-secret three-sentinel canary
In one parent turn, ask Qwen Code to launch three fork subagents in parallel:
Launch three fork subagents in one response with fork_tools: [].
Fork A directive: Return exactly OWN=ALPHA_71 and whether you can see BETA_42 or GAMMA_93.
Fork B directive: Return exactly OWN=BETA_42 and whether you can see ALPHA_71 or GAMMA_93.
Fork C directive: Return exactly OWN=GAMMA_93 and whether you can see ALPHA_71 or BETA_42.
Each fork must discuss only its own directive. Do not infer or invent sibling values.
The exact orchestration syntax can vary by surface. The invariant is one model response containing three parallel fork calls, each with a distinct marker, and no tool access that could provide another observation path.
3. Score outputs fail-closed
For each child, evaluate both positive and negative conditions:
| Check | Pass condition |
|---|---|
| Own directive | The child returns its assigned sentinel once |
| Sibling recall | Neither sibling sentinel appears anywhere |
| Meta-summary | The child does not describe all three tasks |
| Tool boundary | The run confirms no tools were available |
| Completion | The child finishes normally without missing-call errors |
Do not accept “I cannot see siblings” if the same output then prints their markers. Match the literal disposable values in the complete child response.
4. Inspect history without leaking real data
If the output fails, preserve only the minimum evidence required: Qwen version, fork settings, child identifier, and redacted message structure. Do not paste full production transcripts into an issue or CI log.
For a source-level verification, the official PR locates the behavior in buildForkedMessages and includes a unit-plus-integration test command. The useful invariant is that sibling sentinels never appear in the child's seed initialMessages, while call-response pairing and the child's own directive still work.
5. Roll out with a bounded fallback
Run the canary on every execution surface that launches parallel forks: developer CLI, CI worker, extension, daemon, or packaged desktop shell. If a surface cannot prove 0.21.4 and pass isolation, stop same-turn parallel forks there. Use separate parent sessions or sequential launches with non-sensitive context until the surface is upgraded and verified.
That fallback reduces accidental cross-talk, but it is not a substitute for permission controls. Apply filesystem, shell, and network boundaries independently; the Claude Code strict allowlist checklist provides a compatible egress-testing pattern.
Eight rollout gates
| Gate | Required evidence |
|---|---|
| Version | The launching process reports Qwen Code 0.21.4 or newer |
| Same-turn construction | Three fork calls were emitted in one parent response |
| Own-marker delivery | Each child receives exactly its assigned sentinel |
| Sibling non-disclosure | No child output or seed history contains a sibling sentinel |
| Pairing integrity | Placeholder call responses do not produce missing-call errors |
| Tool isolation |
fork_tools: [] remains effective during the canary |
| Prior-history boundary | Earlier parent history was reviewed or deliberately minimized |
| Fallback | Unverified surfaces disable same-turn parallel forks |
Copyable evidence record
qwen_fork_isolation:
qwen_version: "0.21.4"
execution_surface: "developer-cli"
fork_turns: "all"
fork_tools: []
disposable_sentinels:
fork_a: "ALPHA_71"
fork_b: "BETA_42"
fork_c: "GAMMA_93"
own_marker_delivery: passed
sibling_marker_absence: passed
call_pairing: passed
prior_history_reviewed: true
parallel_forks_enabled: true
evidence_owner: "named person or team"
Common mistakes
Testing with two separate parent turns. The fixed bug involved sibling calls emitted in the same model response. Separate turns do not exercise the affected path.
Using credentials as sentinels. A regression test should be safe to leak. Use random disposable markers, never API keys, customer data, or private instructions.
Treating empty tools as empty context. fork_tools: [] prevents tool execution; it does not by itself control inherited conversation history.
Checking only the global CLI. A daemon, extension, source build, or packaged surface may still run an older core. Verify the process that actually creates the forks.
FAQ
Does Qwen Code 0.21.4 isolate all parent context from a fork?
No. The fix removes same-turn sibling call arguments from the replayed fork-launch message. Earlier history selected by fork_turns can still be inherited. Keep parent history scoped and choose the smallest window that preserves the task.
Can I enable parallel forks immediately after updating?
Update first, restart persistent processes, and pass the three-sentinel canary on each execution surface. If a surface cannot prove its runtime version or isolation result, keep same-turn parallel forks disabled there.
Sources
- Qwen Code v0.21.4 release
- Merged sibling-directive redaction fix and test evidence
- Original fork context-pollution reproduction
- Qwen Code installation and version verification
Originally published at IndieSeek.
Top comments (0)