Troubleshoot duplicate messages and missed answers

Note

Before troubleshooting, review Context distribution in the standard harness and Design best practices to avoid duplicate messages. These articles explain the context model and preventive design guidance that this article builds on.

Use this guidance to investigate a standard harness agent that sends more than one answer, misses part of a request, or returns to an old question after a different request was handled.

A maker only sees the symptom in chat. The cause is almost always a context mismatch: the user saw one thing, but the component that continued the plan had a different view of what was already answered. This guidance helps you find and fix this mismatch.

In this article, a component is anything the orchestration layer can call in a plan: a topic, a subagent (a child or connected agent), a call to knowledge, or a generative answers node. The user can be shown a message by the top-level agent, by a node inside a topic (a message, question, or Adaptive Card node), or by a subagent. It's important to identify precisely which component communicated with the user. A point of view is the active context a component reasons from. Duplicate messages and missed answers happen when these points of view disagree about whether the user's request or question was answered.

Favor moving user communication to the orchestration layer

Most duplicate messages and missed answers occur when a component communicates with the user on its own, and the orchestration layer's context no longer matches the response the user received. Before you troubleshoot an individual case, review your design for optimal orchestration. For each component, decide whether it really needs to communicate with the user directly, or whether you can move all user communication to the orchestration layer through input collection, outputs, and instructions.

Work through the components you use:

  • Do you use topics? Prefer holding the topic's user communication in the orchestration layer. Collect what the topic needs as inputs, return what it produced as outputs, and let the orchestration layer write the response. A topic that only reads and returns values can't answer twice. Learn more in Design topics as mini-agents that avoid duplicate messages.

  • Do you use subagents (child or connected agents)? Prefer passing a scoped input and reading the agent's outputs, so the parent agent writes the response. Learn more in Design subagents that avoid duplicate messages.

Tip

Move user communication from as many topics and subagents as possible to the orchestration layer. Many of the cases in the following sections disappear once a single component owns the response. If some topics, child agents, or connected agents must still communicate with the user directly, use the guidance in this article for the remaining cases.

How to investigate

Start every duplicate-message or missed-answer investigation the same way. You see only the symptom, so gather evidence that shows what each component knew.

  1. Reproduce the issue and save the visible transcript so you have a record of exactly what the user saw and in what order.
  2. Use an activity map to identify the topics, tools, agents, and knowledge sources that the orchestration layer selected for that turn.
  3. For each selected component, compare what it sent to the user and what it returned to the orchestration layer as outputs.
  4. Compare the transcript, activity map, and component outputs to find the context mismatch. For example, a component communicated with the user but didn't report that fact, two components answered the same request, or a later step received incomplete context and answered again.
  5. Match the context mismatch to a root cause in the next section.

Tip

An activity map is the fastest way to compare the plan that the orchestration layer ran with what the user actually experienced. Start with the activity map and then review each component's outputs.

Capture this evidence before you change anything.

Evidence Why it matters
Visible transcript Shows what the user saw. This symptom is what you're explaining.
Activity map Shows the plan the orchestration layer ran.
Topic inputs Shows what the orchestration layer sent to the topic.
Topic variables Shows what the topic captured internally.
Topic outputs Shows what the topic returned to the orchestration layer.
Adaptive Card payload and captured action values Shows which visible values and choices became variables or outputs.
Subagent inputs Shows whether the subagent received too much, too little, or the wrong context.
Subagent outputs Shows what the subagent returned to the orchestration layer.
Instructions and descriptions Top-level and subagent instructions, and topic and subagent descriptions, affect agent behavior.

Find the root cause

Duplicate messages can have different root causes even when they look the same in chat, so the transcript alone isn't enough to identify the cause. A component might not report that it answered, two components might answer the same request, or a subagent might answer based on the full parent context. To identify the root cause, use the activity map to determine which steps the plan ran, and then compare those steps with each component's design and outputs.

Find the row that matches your evidence, and then read that root cause's section.

What the activity map shows What the design shows Root cause Best fix
A topic, tool, or agent wrote the answer, and then another step answered again (orchestration layer, knowledge, or a child or connected agent) The component returned no answered-state output Answered, but not reported back Return an answered-state output
Two components each wrote the answer Both are instructed or configured to answer Two response owners Choose one response owner
A connected agent or child agent produced the second answer It received the full parent context A subagent answered from full parent context Scope the inputs and exclude context
The agent refetches data or asks for a value it already had A complete fetch was only partly returned, or the value aged out of a long conversation Context lost Return the full result, or restore the value
The old question or card reappears after a different answer A question or card was still open when the new request arrived Abandoned prompt Handle the breakout
The same topic ran twice in the turn An interception redirect answers, and the planner runs it again Double execution via interception Enrich-and-continue, or end topics after the redirect

Tip

When a component answers the user directly, check whether it returns an output that tells the orchestration layer what it answered. Without that output, the orchestration layer might treat the request as unanswered and respond again.

Add the top-level instruction that the fixes rely on

Most of the following suggestions rely on a top-level instruction that tells the orchestration layer to check component outputs before answering. Add this instruction once at the top level.

Whenever any topic or agent is called, always look for the 'answered' boolean output before deciding what to reply. Topics and agents have their own channel of communication with the user. If 'answered' is true, always assume that the request has been answered appropriately using at least one of the output variables, and check which ones based on the output description. Do not give an awkward acknowledgement of the answered content. Only provide the unanswered outputs, and continue the conversation naturally with the next step.

This sample instruction works whether or not a component communicates directly with the user. Edit and customize it for your agent. In this example, the term channel doesn't refer to an integration channel. It's a prompting device that tells the orchestration layer the user might have already seen the answer through another component.

Learn more in Design a robust top-level instruction to avoid repeated messages.

A topic or subagent already answered, but the agent answers again

What you see: In a multistep conversation, after a topic or subagent runs, or after an Adaptive Card answers a question or collects input, the agent answers again, shows a second version of the answer, or says it doesn't have the answer. The repeat can come from the orchestration layer, a knowledge step, or another agent.

Root cause: Answered, but not reported back. A topic, subagent, tool, or Adaptive Card successfully communicated with the user, but it didn't return an output telling the orchestration layer that the request was answered, nor what the answer was. From the orchestration layer's point of view, that part of the request is still open, so it answers again, or a later step such as knowledge answers it. The component reached the user, but the orchestration layer never learned it happened.

Knowledge answers something already handled: When a topic shows an order status in a card but doesn't return an answered-state output, a later knowledge step still sees the order status request in context. The knowledge step then gives general guidance about checking order status, so the user sees the specific status followed by generic advice. The root cause is the same—the topic didn't report back. Return an answered-state output from the topic so that the knowledge step knows the request was already answered.

A generative answers node answered from a topic: A generative answers node receives the parent context along with its input, so the node behaves like top-level knowledge. This situation can cause duplicate answers in two ways:

  • The node answers a request that the parent context shows as unanswered, even though another component already handled it.
  • The node's answer stays inside the topic. If the topic doesn't return an answered-state output, the orchestration layer doesn't know that the node answered the request. A later step then answers the request again.

Both of the above situations trace back to answered-state. To prevent duplicate answers, return an answered-state output from the topic so the orchestration layer knows the node answered. Also, ensure upstream components report what they answered so that the node doesn't treat those requests as unanswered. Learn more about how a generative answers node fits the context model in Handle generative answers nodes.

A card collected the user's choice, but the topic re-asks it: A topic asks a question with Ask with Adaptive Card, and the user answers by selecting a button within the same topic. The orchestration layer receives the card's text through the conversation, but it doesn't receive the buttons, the user's selection, or the resulting choice. If the topic exits without reporting the selection, the orchestration layer asks the same question again, often as plain text. The same root cause applies, in this case applied to a choice. Return an output that reports the selection, such as choiceReceived and the selected value, so the orchestration layer knows the user already answered.

Example: A user asks a two-part question: "What is my account balance, and what is the price of the latest Surface Laptop?"

The account balance topic shows the balance in an Adaptive Card: Account balance: $125.00

The plan still needs to answer the laptop question. Because the topic returned no outputs, the orchestration layer has no reliable context that the balance was already shown, so it attempts to answer it in its final response. The user sees the following:

[Adaptive Card showing Account balance: $125.00]

I don't have access to your account balance, but the latest Surface Laptop starts at...

The topic answered the user. The orchestration layer didn't receive enough context about that answer, so its knowledge step tried to reply to both questions.

Remedy: Configure each component to return outputs that tell the orchestration layer whether it answered the user and what information it provided. The orchestration layer uses this output to avoid answering the same request again.

Make the following changes so this pattern works whether the component responds directly or returns information for the orchestration layer to present:

  1. Return an answered-state output that records what happened.
  2. Add an instruction to the component's description that defines a successful run.
  3. Add the top-level instruction so the orchestration layer checks those outputs before it answers.

For a topic, return an answered-state output and the displayed value if a later step needs it.

Output Example description
answered True if the user already received a satisfactory answer to the account balance request in this topic.
balanceValue The account balance that was already provided to the user within the topic. It doesn't need to be provided to the user again unless the user asks for it.

Add an instruction to the topic description as follows:

This topic handles account balance requests. 
If its answered output is true, the user has already received their response and it should not be answered again.

A subagent reports the same way with its own outputs, answered and interactionSummary. Learn more in Design subagents that avoid duplicate messages.

Add the top-level instruction that the fixes rely on. If the component writes the answer, it returns its answered-state output and value. If it only returns outputs, the orchestration layer writes the answer from them.

The same answer appears twice

What you see: The user receives the same answer twice, often a precise answer followed by a general restatement.

Root cause: Two response owners. More than one component is instructed or configured to write a user-facing answer for the same request. Both respond.

How to recognize it in your design: One of these situations is usually present:

  • Top-level instructions say to call a topic and give the answer.
  • A topic description explains both when to use the topic and how to present the answer, so the orchestration layer handles presentation separately.

Example: The top-level instruction reads:

When the user asks about their account balance, call the Account balance topic and give the balance.

The topic already shows the balance in a card. Adding "and give the balance" prompts the orchestration layer to repeat the balance, so the user sees it twice, once in the card and restated by the orchestration layer.

Instead, use a routing-only instruction:

When the user asks about their account balance, call the Account balance topic.

Remedy: For each part of the request, pick one response owner:

  • The component writes to the user and returns outputs describing what it answered.
  • The component returns outputs only and the orchestration layer writes the answer.

Whichever owner you pick, add the top-level instruction that the fixes rely on so that a newer model checks outputs before answering.

A subagent re-answers a request that was already handled

What you see: A connected agent or a child agent answers a request that another topic, card, or agent already handled.

Root cause: A subagent answered from full parent context. The orchestration layer generates inputs for every step, and subagents also receive conversation context. If a subagent receives the full parent context, and that context contains a request but no answer, the unanswered request can look pending even if another component answered the user. As a result, the subagent answers the request again.

For both connected agents and child agents, scope what the agent works on. These steps apply to both types of agents:

  • Pass a scoped input that names only the part this subagent should handle.
  • Anchor the subagent's instructions to that input.
  • Return outputs that tell the parent whether the user was already answered.

Connected agent

A connected agent has a setting to indicate whether it receives the parent's conversation context. Turn that setting off and pass only a scoped input, so the agent sees only the request you intend.

Example: A benefits topic answers the user's benefits question and shows the answer. The plan then calls an HR connected agent for a separate payroll question but passes the full conversation context. The connected agent still sees the benefits question in the context, assumes it's unanswered, and answers it again. Send only the part it should handle in a scoped input, and write the description for the parent because the parent generates the value.

Input Description (parent audience)
scopedRequest The specific request this agent should fulfill.

If a connected agent can handle only part of the request, it returns what it handled and names what remains. A subagent shouldn't guess which agent handles the rest.

Output Example description
answered True when the user already received an answer to their scopedRequest.
interactionSummary A short summary of the response that was delivered to the user.
openQuestions Any part of the user's request that remains unanswered, so the orchestration layer can complete it and continue tool chaining.

Child agent

A child agent runs inside the parent and always receives the parent's conversation context. Unlike a connected agent, it has no setting to exclude that context, so a scoped input is your only way to keep it focused.

Example: A topic resets the user's password and shows the confirmation. The parent then calls an IT child agent to handle "how do I connect to the VPN?" Because the child agent inherits the full conversation, it also sees the password-reset request, treats it as unanswered, and answers it again. Scope the work with an explicit input. Write the input description for the parent because the parent fills the value.

Input Description (parent audience)
scopedRequest The specific request this agent should fulfill.

Anchor the child agent's instructions to that input, so it works from the scoped request and ignores anything else that resembles an initial request.

Fulfill the request in the scopedRequest input.
Treat it as your initial request and ignore any other initial requests in the conversation.

Then, return the same outputs the connected agent returns, answered, interactionSummary, and openQuestions, so the parent knows what happened. The top-level instruction that the fixes rely on already tells the orchestration layer to check those outputs before it answers, so you don't need a separate per-agent instruction. Learn more about this pattern, including the silent-subagent variant and the findings output, in Design subagents that avoid duplicate messages.

Write each description for the point of view that reads it

These points of view are important to consider when you design a subagent. Confusing them is a common cause of incorrect context.

Surface Point of view that reads it
Subagent description The parent orchestration layer, to decide when and how to use the subagent.
Subagent instructions The subagent, while reasoning within its own context.
A topic or tool description inside the subagent The subagent's own orchestration layer, not the parent directly.
Subagent input descriptions The parent, to generate the values sent to the subagent.
Subagent output descriptions The parent orchestration layer, to interpret what the subagent returned.

The agent refetches or asks again for information it already retrieved

What you see: Later in a session, the agent refetches data it already retrieved, or asks the user again for a value they already gave. The user experiences it as a missed answer. The agent acts as if it never had the value.

Root cause: Context lost. The value was available earlier, but it's no longer in the active context, so the plan fetches or asks again. This problem happens in two ways:

  • A complete fetch was only partly returned. A topic or subagent called a connector that returned a full set of data, used part of it to answer the immediate question, and returned only that answer to the orchestration layer. The rest of the fetched data never entered the main context, so a later request for another field, row, or detail from the same fetch can't be served from context, and the plan refetches or asks the user.

  • The value aged out of a long conversation. A value the user gave, or a component retrieved, several turns ago is no longer in the active context, so the plan asks or fetches again.

Example: A user asks about an order: When will order 4821 arrive?

An order-details topic calls a connector that returns the full order: ship date, carrier, tracking number, and line items.

The topic answers with the ship date and returns only that answer to the orchestration layer: "Your order ships Tuesday and arrives Thursday."

Later in the same conversation, the user asks: "What's the tracking number?"

The tracking number was in the original fetch, but the topic didn't return it, so it isn't in the top-level context. The orchestration layer can't answer from context, so it calls the connector again or tells the user it doesn't have the tracking number.

Remedy: The fix depends on the mechanism:

  • For a partial return: Return the whole fetched result, not just the immediate answer. A result can include multiple fields, many rows, and long text. Return the complete result as output because a later turn might need information beyond the part that answers the current question.

  • For a value that aged out: Use a context rehydration strategy. Store values that must survive a long conversation in a global variable, and return those values when the plan needs them.

Learn more in Restore context in long conversations.

An open question or card returns after a different request was handled

What you see: The agent asks a question or shows a card. The user replies with a different request. The agent answers that request. Then, the original question or card appears again.

Root cause: Abandoned prompt. This use case is a pseudo-duplicate. The topic is still waiting for its answer. When the user sends a new request instead of answering, the orchestration layer can fulfill the new request. But the unanswered question or card remains active and appears again.

Note

This problem looks like a duplicate, but nothing ran twice. The topic is still waiting for its original answer, so the fix differs from the other root causes—handle the abandoned prompt rather than adjust outputs.

Most of the time, letting the user change course mid-question is the behavior you want. Only fix this problem when the returning prompt genuinely confuses the user.

Example: A support topic asks the following, with options shown as text and buttons:

Which category is your issue: Billing, Technical, or Account?

[Billing] [Technical] [Account]

Instead of choosing a button, the user types: "Actually, what's my current account balance?"

The agent answers the balance question. Then, because the category question is still waiting, the agent shows the category question again, which looks like a duplicate prompt to the user.

Remedy: Start by deciding whether you need a prompt node at all. Because an open question or card competes with the orchestration layer's context, consider collecting the value as an input the orchestration layer gathers, instead of a question node or Ask with Adaptive Card. With an input, the orchestration layer collects the value as part of the conversation and there's no separate prompt to abandon. The trade-off is the interface: the input is gathered as text, not by button elements. Similarly, you can't move a card up to be re-rendered because Adaptive Card content placed in an output isn't rendered as a card. The orchestration layer reformats it per your instructions, and button options can become numbered choices.

If you keep a question with options, give the user an explicit way out:

  • Add a Cancel or Something else option to the question, and save the response in a variable such as categoryChoice.
  • Add a condition on categoryChoice. When it's the Cancel option, end the topic so no prompt is left waiting:
Question: Which category is your issue?
Options: Billing, Technical, Account, Something else
Save response as: categoryChoice

Condition: categoryChoice is "Something else"
  End topic

If you keep an Ask with Adaptive Card, use Recognize Intent for the breakout pattern. A typed request while the card is still open ends the card instead of leaving it active.

If a plan must stop staying active inside another plan, use On Plan Complete followed by End all topics.

The same topic runs twice in one turn

This edge case commonly appears in agents migrated from intent-based routing. Work through the most common root causes first.

What you see: The same topic runs twice in one turn, once from your own interception routing and once from the orchestration layer.

Root cause: Double execution via interception. Input interception is meant to enrich context and then let the message continue. When it instead redirects to a topic that answers, the original message still reaches the orchestration layer, which handles the same request again. This behavior most often appears when you recreate intent-based topic routing inside the standard harness.

Tip

If the activity map shows the same topic running twice in one turn, once from your interception routing and once from the orchestration layer, you have double execution via interception.

Example: The maker sees the answer appear, then a near-duplicate of it:

  1. The incoming message is intercepted.
  2. The interception topic redirects to a topic.
  3. The topic answers.
  4. The interception topic finishes.
  5. The orchestration layer also handles the original message and calls the same topic again.

Remedy:

  • If the interception only enriches context, set variables and do nothing else. Let the message continue to the orchestration layer.
  • If the interception redirects and owns the request, end all topics after the redirect so the same request isn't handled twice.
  • Don't recreate intent-based topic routing unless the use case requires it. The orchestration layer is the planning layer.