Bug Description
When a user clicks a button (Action.Submit) on an adaptive card posted by a
Teams bot, the adapter's card.action invoke handler always replies with an
empty AdaptiveCardInvokeResponse (value: ""). Teams treats this as an
unsatisfactory/malformed invoke result, renders the generic "Unable to reach
app. Please try again." banner, and retries the invoke. The retry causes
the registered onAction handler to run a second time, so any side effect the
handler performs (post a message, create a ticket, resume a workflow, etc.)
happens twice for a single click.
Steps to Reproduce
- Build a Teams bot with
@chat-adapter/teams.
- Post an adaptive card containing a
Button (rendered as Action.Submit):
<Card>
<Text>Was this helpful?</Text>
<Actions>
<Button id="thumbs_up" label="👍" value={JSON.stringify({ id: "x" })} />
<Button id="thumbs_down" label="👎" value={JSON.stringify({ id: "x" })} />
</Actions>
</Card>
- Register a handler:
bot.onAction(["thumbs_up", "thumbs_down"], async (event) => {
console.log("clicked", event.actionId);
await event.thread?.post("received");
});
- In Teams, click the button once.
Expected Behavior
- The button click is acknowledged; no error banner.
- The
onAction handler runs exactly once.
Actual Behavior
- Teams shows "Unable to reach app. Please try again." on the card.
- The
onAction handler runs twice (Teams retries the invoke). Logs show
the same actionId / activity processed two times, and any side effect is
duplicated.
Code Sample
Chat SDK Version
4.29.0
Node.js Version
No response
Platform Adapter
Microsoft Teams
Operating System
None
Additional Context
The card.action event handler returns a fixed invoke response whose value
is an empty string:
// packages/adapter-teams/src/index.ts (card.action handler)
this.app.on("card.action", async (ctx) => {
this.cacheUserContext(ctx.activity);
await this.handleAdaptiveCardAction(ctx);
return {
statusCode: 200,
type: "application/vnd.microsoft.activity.message",
value: "", // ← empty message value
};
});
Bug Description
When a user clicks a button (
Action.Submit) on an adaptive card posted by aTeams bot, the adapter's
card.actioninvoke handler always replies with anempty
AdaptiveCardInvokeResponse(value: ""). Teams treats this as anunsatisfactory/malformed invoke result, renders the generic "Unable to reach
app. Please try again." banner, and retries the invoke. The retry causes
the registered
onActionhandler to run a second time, so any side effect thehandler performs (post a message, create a ticket, resume a workflow, etc.)
happens twice for a single click.
Steps to Reproduce
@chat-adapter/teams.Button(rendered asAction.Submit):Expected Behavior
onActionhandler runs exactly once.Actual Behavior
onActionhandler runs twice (Teams retries the invoke). Logs showthe same
actionId/ activity processed two times, and any side effect isduplicated.
Code Sample
Chat SDK Version
4.29.0
Node.js Version
No response
Platform Adapter
Microsoft Teams
Operating System
None
Additional Context
The
card.actionevent handler returns a fixed invoke response whosevalueis an empty string: