Every mechanism so far lived inside one agent's loop. Split a task across two specialized agents and a coordinator that hands results between them, and a new failure mode appears that has nothing to do with either agent being wrong — the handoff itself.
Research agent returns:
{"topic":"Mount Everest","fact":"is the tallest mountain above sea level"}Correct handoff (writer receives result.fact):
Mount Everest is the tallest mountain above sea level.
Broken handoff (writer receives the whole result object):
Mount Everest [object Object].
Switch topics. The research agent's output is a structured object — a topic and a fact, two separate fields. The correct handoff passes the fact field alone to the writer. The broken one passes the whole object instead, and nothing crashes — it just stringifies into garbage.
A coordinator routes a task to a specialized agent, then hands that agent's output to the next one. The interface between them is usually just JSON (JavaScript Object Notation) — a shape, not a compile-time contract:
- — the specialized agent that composes the final sentence.
- subject — the topic string passed into the writer.
- fact — the plain string of information that's supposed to be passed alone, not wrapped in an object.
- A mismatched handoff fails silently
If the coordinator passes an entire
{topic, fact}object wherefactwas supposed to be a plain string, JavaScript (like most dynamically-typed interchange formats) doesn't throw — it silently calls the object's default string conversion, producing"[object Object]". - The bug lives in the handoff, not either agent
Neither agent did anything wrong on its own; it's what the coordinator handed off between them that broke, and it fails silently instead of loudly.
Mount Everest [object Object].
The Pacific Ocean [object Object].
Saturn [object Object].
Three completely different topics, three completely identical failures. The garbage text doesn't depend
on which fact was lost — [object Object] is what any object looks like once stringified, so this
exact bug looks identical no matter which specific handoff produced it, which is part of why it's
genuinely hard to debug from the output alone.
The handoff for "Mount Everest", done two ways:
- What the research agent actually returns
{ topic: "Mount Everest", fact: "is the tallest mountain above sea level" }— one object, two fields. - Correct handoff: pass the fact field alone
writer("Mount Everest", result.fact)→ "Mount Everest is the tallest mountain above sea level." - Broken handoff: pass the whole object
writer("Mount Everest", result)→ "Mount Everest [object Object]." — the sentence has the right shape and the right subject; only the one field that mattered is gone.
Find the topic, among the three, whose correctly-written sentence mentions rings.
This chapter's bug was a single misplaced argument — real multi-agent systems fail this way constantly, because every handoff between agents is another place a schema mismatch, a missing field, or a misunderstood contract can slip through untyped. Multi-agent frameworks address this with explicit schemas at every handoff (the same structured-output idea from Part XVII's function-calling chapter, applied between agents instead of between a model and a tool). The capstone wires everything this part covered — planning, a tool call, and memory — into one working loop that solves a task no single call could handle alone.