A Teams bot has four places to break - find yours first
A Microsoft Teams bot is four systems chained together: the Teams client, the Azure Bot resource, the Bot Framework connector service, and your messaging endpoint. "Bot not responding" can mean any link in that chain is broken, and each one has its own symptom.
Last verified: August 2026 against Microsoft Learn (Teams platform documentation, Azure AI Bot Service documentation) and the Teams app manifest schema. Error codes and strings quoted are the literal values the platform returns.
| What you see in Teams | Most likely link | Go to |
|---|---|---|
| App cannot be uploaded / does not appear in the app store | Manifest or admin policy | Sections 1 and 6 |
| Bot installs, messages send, bot never replies, no error | Endpoint unreachable, or channel not enabled on the Azure Bot | Sections 2 and 3 |
| Bot replies in personal chat but not in a channel | Not @mentioned, or mention text not stripped | Section 7 |
| Bot replies sometimes, or replies twice | Endpoint too slow (15-second limit) or retries | Section 8 |
Your endpoint logs show 401 Unauthorized on inbound or outbound | App ID / secret / tenant type mismatch | Sections 4 and 5 |
Proactive message fails with 403 or 404 | Bad conversation reference or bot removed | Section 9 |
The fastest way to localise the break is to check two logs side by side: your endpoint's access log, and the Azure Bot resource's Test in Web Chat blade. If Web Chat works and Teams does not, the bot and endpoint are fine and the fault is in the Teams channel, manifest or tenant policy. If Web Chat also fails, Teams is innocent - fix the endpoint and credentials first.
1. The manifest: botId must equal the Microsoft App ID, byte for byte
The Teams app package is a zip containing manifest.json, color.png and outline.png. The manifest schema reference is strict, and Teams validates the package at upload. The field that causes most "installs but never responds" reports is bots[].botId: it must be the Microsoft App ID (the Entra application ID) of the Azure Bot resource - not the bot handle, not the resource name, not the tenant ID.
{
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.16/MicrosoftTeams.schema.json",
"manifestVersion": "1.16",
"version": "1.0.0",
"id": "00000000-0000-0000-0000-000000000000",
"bots": [
{
"botId": "00000000-0000-0000-0000-000000000000",
"scopes": ["personal", "team", "groupChat"],
"supportsFiles": false,
"isNotificationOnly": false
}
],
"validDomains": ["yourbot.example.com"]
}Things the validator and the runtime check that trip people up:
| Field | Rule | Symptom when wrong |
|---|---|---|
bots[].botId | Must match the App ID of the Azure Bot exactly | Installs cleanly; messages vanish; nothing reaches your endpoint |
bots[].scopes | Literal values personal, team, groupChat | App missing from the 'Add to a team' option; bot absent in group chats |
supportsFiles | Only honoured in personal scope | File attachments silently dropped in channels |
isNotificationOnly | true means the bot never receives messages | One-way bot that ignores everyone by design |
id | A GUID; commonly set equal to the App ID | Upload rejected if not a valid GUID |
validDomains | Needed for tabs, task modules, sign-in | Auth card or tab shows blank / blocked |
| Icons | color.png 192x192, outline.png 32x32, at zip root | Package validation failed at upload |
Use the Developer Portal for Teams (dev.teams.microsoft.com) to build and validate the package: it flags schema errors with the field path instead of making you guess. If you are not building from scratch, Conferbot's Teams channel generates a valid package for you.
2. The Azure Bot resource: is the Teams channel actually enabled?
An Azure Bot resource talks to nothing until a channel is enabled on it. In the Azure portal open the bot resource, go to Channels, and confirm Microsoft Teams is listed with a healthy status. If it is not there, add it and accept the terms. A bot that works perfectly in Test in Web Chat and is silent in Teams, with nothing arriving at your endpoint, is very often just this - the Teams channel was never turned on, or was removed when the resource was recreated.
While you are on the resource, check the Configuration blade for two more settings covered next: the Messaging endpoint and the Microsoft App ID. Also note the Bot type shown there - it decides how authentication works in section 5. Microsoft's walkthrough is at Create a bot for Teams.
Teams channel-specific settings
The Teams channel page has its own toggles: Calling (a webhook for voice/video - leave off unless you use it), and Publish (for the store). Neither blocks plain text messaging, but a calling webhook URL pointing at a dead host generates errors in the channel health view that look alarming and are unrelated to chat.
3. The messaging endpoint: HTTPS, public, /api/messages, and reachable right now
The Bot Framework connector delivers every Teams message as an HTTP POST to the Messaging endpoint configured on the Azure Bot. By convention it ends in /api/messages (the SDK templates route there), but it can be anything - what matters is that the URL in Azure and the route in your code are identical, including the path.
| Requirement | How to check | Failure you will see |
|---|---|---|
| HTTPS with a valid, complete chain | openssl s_client -connect host:443 shows Verify return code: 0 (ok) | Silent: connector cannot deliver; nothing in your log |
| Publicly routable - no localhost, no LAN IP | curl -i -X POST https://host/api/messages from outside | Silent, or Web Chat shows a generic failure |
| Accepts POST on the exact path | Your test returns 401 (good - auth ran) not 404/405 | 404/405 in your access log |
| Returns within 15 seconds | Time your handler under load | Intermittent silence and duplicate replies |
| Process is actually running | Check the host, container or App Service status | 502 / 503 from your reverse proxy |
A quick sanity test: curl -i -X POST https://yourbot.example.com/api/messages -H "Content-Type: application/json" -d "{}". A correctly wired endpoint answers 401 Unauthorized because the request carries no Bot Framework token - that 401 is a good sign. A 404, 405, connection refused or TLS error is the bug.
For local development use a tunnel (ngrok http 3978 - 3978 is the SDK default port) and paste the HTTPS tunnel URL plus /api/messages into the Azure Bot configuration. Every time the tunnel restarts on a free plan, update the endpoint again; a surprising share of "it stopped working overnight" reports are stale tunnel URLs. The same network traps that hit every webhook - firewalls, Cloudflare WAF rules, IPv6 records, trailing-slash redirects - are covered in our webhook debugging guide.
4. App ID and client secret: the 401 that arrives after the secret expires
Your bot authenticates to the Bot Framework with the Microsoft App ID and a client secret created on the Entra app registration (an OAuth client-credentials flow underneath) (MicrosoftAppId / MicrosoftAppPassword in the SDK configuration). When either is wrong, your endpoint rejects inbound activities and your outbound replies are rejected by the connector - and both show up as 401.
The expiry nobody schedules
Entra client secrets have a mandatory expiry - at most 24 months, and the portal defaults to less. When the secret expires, the bot keeps receiving activities (inbound validation uses the App ID and Microsoft's public keys) but every reply fails with an unauthorized error from the token endpoint, so from the user's side the bot simply goes quiet on a date nobody remembers choosing. Open the app registration, Certificates & secrets, and look at the expiry column before you debug anything else. Create a new secret, update the bot's configuration, restart, and put the next expiry in a calendar.
Other credential mistakes, in order of frequency:
- Copying the secret's Secret ID column instead of the Value column (the value is only shown once, at creation).
- Trailing whitespace or quotes from a
.envfile. - Using the App ID from a different registration - typical when a resource was recreated and the old ID lingers in config.
- Rotating the secret in Entra but not redeploying the bot.
Microsoft's guide for this class of problem is Troubleshoot Bot Framework authentication, which walks through checking the App ID, secret and endpoint in order.
5. Single-tenant vs multi-tenant: the other 401
An Azure Bot is created as one of three bot types: Multi Tenant, Single Tenant or User-Assigned Managed Identity. The type is fixed at creation and must match how your code authenticates. A mismatch produces 401 Unauthorized on every activity, with nothing else obviously wrong - the App ID is right, the secret is fresh, the endpoint is reachable.
| Bot type | Code must set | Typical mismatch |
|---|---|---|
| Multi Tenant | MicrosoftAppType=MultiTenant; no tenant ID required | Code configured as single-tenant with a tenant ID; tokens requested from the wrong authority |
| Single Tenant | MicrosoftAppType=SingleTenant and MicrosoftAppTenantId=<tenant GUID> | Tenant ID missing; older SDK that does not support single-tenant; app registration is actually multi-tenant |
| User-Assigned Managed Identity | MicrosoftAppType=UserAssignedMSI, App ID = identity client ID, no secret | Running outside Azure where the identity is unavailable |
Check the type on the Azure Bot's Configuration blade and the app registration's Supported account types. Older SDK versions (Bot Framework SDK before 4.15 or so) do not understand single-tenant at all; if you inherited a bot and a new single-tenant resource was created for it, upgrading the SDK is part of the fix. If you cannot change the code, recreate the Azure Bot with the type the code expects - there is no in-place conversion.
6. Sideloading disabled and app permission policies
If you cannot find the option to upload your app package in Teams at all, nothing is wrong with your bot. Custom app upload (sideloading) is controlled by the tenant admin through two separate settings, and both must allow it:
- Org-wide app settings in the Teams admin center: Teams apps > Manage apps > Org-wide app settings, where custom apps can be allowed or blocked for the whole tenant.
- App setup policies: Teams apps > Setup policies, where the Upload custom apps toggle is set per policy and policies are assigned to users. The Global (Org-wide default) policy ships with it off in many tenants.
Microsoft documents the two layers in Manage custom app policies and settings, and the developer-side view in Upload your app in Teams. Policy changes can take several hours to propagate to clients, and signing out and back in to Teams is usually needed before the upload option appears.
If you are a developer in a locked-down corporate tenant, the practical route is a free Microsoft 365 developer tenant where you are the admin, or asking the admin to publish the app to the org catalog instead of sideloading it. If the bot is an HR or IT helpdesk, our Teams HR chatbot guide covers the catalog route.
Installed by some users, blocked for others: app permission policies
Once an app is in the tenant, app permission policies decide who can use it. An app can be allowed org-wide but blocked for a group of users by the policy assigned to them; those users see the app greyed out, or do not see it at all, or install it and get no responses because the bot is blocked at the policy level. Conversely a tenant admin can block a specific app in Manage apps, which stops it for everyone regardless of policy.
When the bot is blocked after installation, outbound replies from your bot can fail with a 403 whose body names the cause:
{
"error": {
"code": "BotDisabledByAdmin",
"message": "The tenant admin disabled this bot"
}
}The status codes the Teams conversation APIs return are listed in Messages in bot conversations; BotDisabledByAdmin and BotNotInConversationRoster are the two 403 reasons you will meet most. The fix is administrative: the admin allows the app in Manage apps and in the permission policy assigned to the affected users. Our guide to Slack and Teams bots for employee support covers the rollout side of this in more depth.
7. Replies in personal chat, ignores channels: the @mention rule
In a personal (one-to-one) chat your bot receives every message. In a team channel or group chat it receives a message only when it is @mentioned, per Channel and group chat conversations with a bot. Users who type a question in a channel without mentioning the bot get nothing, and from their side it looks broken. That is by design, and the cure is user education plus the next two fixes.
Strip the mention before you parse
When the bot is mentioned, the incoming activity.text includes the mention itself, for example <at>HelpBot</at> reset my password. Intent matching against that string fails unless you remove the mention first. The SDK provides a helper: TurnContext.removeRecipientMention(activity) (Node/JavaScript) or turnContext.Activity.RemoveRecipientMention() (C#), which returns the text without the <at> tag. Call it at the top of your message handler and trim the result - a bot that works in personal chat and "misunderstands everything" in channels almost always skipped this. If it misunderstands everywhere, the cause is the model or the content rather than Teams - see our guide on why AI chatbots give wrong answers.
Receive channel messages without a mention: RSC
If the bot genuinely needs to see every channel message (moderation, FAQ auto-answer), request the resource-specific consent permission ChannelMessage.Read.Group in the manifest under authorization.permissions.resourceSpecific, per Resource-specific consent. A team owner grants it at install time, and the admin can restrict RSC tenant-wide - so if the permission is in the manifest and the bot still only hears mentions, check the RSC setting in the admin center.
8. Replies intermittently or twice: the 15-second limit and retries
Teams expects your endpoint to return an HTTP 200 (or 202) to each activity within about 15 seconds. If your handler calls an AI model, a database and a CRM before responding, you will cross that line under load. When the slow step is a tool call into your own systems, the chatbot MCP server guide covers structuring those calls so they can be deferred. The connector treats the delivery as failed, the user may see nothing or a generic error bubble, and a retry can cause your handler to run twice - which is where duplicate replies come from. Behaviour shared with every other platform's webhook: acknowledge first, work second. Our webhook debugging guide shows the pattern in Node.
For long operations, send a typing indicator (context.sendActivity({ type: "typing" })), return from the turn, and deliver the answer as a follow-up message once the work finishes. If you see 429 responses on outbound sends, you are hitting the per-bot, per-thread throttling that Microsoft documents alongside the conversation API status codes; back off and retry with jitter - the general strategy is in chatbot API rate limiting. Published ceilings for WhatsApp, Telegram and Discord are on our platform limits pages if the same service fans out to those channels.
The Emulator is not Teams
The Bot Framework Emulator connects to localhost with no authentication, no Teams channel data, no mentions and no 15-second ceiling. A bot that is flawless in the Emulator can still fail in Teams on credentials, tenant type, manifest and mention handling - every section above this one. Use the Emulator to test conversation logic; use a real Teams tenant to test the integration.
9. Proactive messages fail: conversation references and "conversation not found"
A proactive message is one your bot sends without a user message triggering it - a reminder, an alert, a welcome. It requires a stored conversation reference captured from a previous activity (TurnContext.getConversationReference(activity)) and the matching serviceUrl, because Teams traffic is regional (service URLs look like https://smba.trafficmanager.net/<region>/) and a reply sent to the wrong regional endpoint is rejected. Microsoft's guide: Send proactive messages.
| Error on send | Meaning | Fix |
|---|---|---|
404 ConversationNotFound | Conversation ID does not exist on that service URL, or was deleted | Re-capture the reference; check you stored serviceUrl and conversation.id together |
403 BotNotInConversationRoster | The user uninstalled the bot or it was removed from the team | Handle installationUpdate with action: "remove" and drop the reference |
401 Unauthorized | Credentials wrong, or the service URL was never trusted by an older SDK | Fix credentials per section 4; on old SDKs call MicrosoftAppCredentials.trustServiceUrl |
400 with a user without an existing chat | Personal proactive messages need the bot installed for that user | Install the app for the user first, or use createConversation with the tenant ID |
Welcome messages
To greet users on install, handle the installationUpdate activity (action: "add") or conversationUpdate with membersAdded containing an ID other than the bot's own - the first membersAdded event after install includes the bot itself, and sending a welcome on that one produces a greeting addressed to nobody. Event details are in Conversation events.
The diagnostic checklist, in order
When a Teams bot is not responding, run this sequence and stop at the first failure:
- Test in Web Chat on the Azure Bot resource. Fails: endpoint, credentials or tenant type (sections 3-5). Works: continue.
- Teams channel enabled on the Azure Bot resource (section 2).
- Manifest
botIdequals the App ID;scopesinclude where you are testing (section 1). - Client secret expiry on the app registration (section 4).
- Can you upload / see the app? If not, sideloading or permission policies (section 6).
- Personal chat works, channel does not? Mention rule and mention stripping (section 7).
- Works sometimes? Response time against the 15-second ceiling; idempotency (section 8).
- Proactive only? Conversation reference, service URL, roster errors (section 9).
Two habits prevent most repeat incidents: log every inbound activity type and every outbound non-2xx response from the connector, and put the secret expiry date somewhere a human will see it. Cross-platform, the same discipline applies to Slack, Discord and Telegram bots - the failure lists differ, the method does not. The literal error strings for the platforms that publish full code sets are in our error-code directory.
Running a Teams bot without owning the Bot Framework plumbing
Almost nothing in this guide is about what your bot says. It is about Azure resources, Entra secrets, manifest schemas, tenant policies, mention parsing and connector timeouts - the cost of running a bot inside Microsoft's ecosystem, paid again every time a secret expires or an admin changes a policy.
Conferbot for Microsoft Teams handles the Azure Bot, endpoint, credentials and app package for you: you build the conversation in a visual editor, add your own content with the AI chatbot builder, and the same flow runs in Teams, Slack, WhatsApp, Telegram and your website. When a question needs a person, it hands off to live chat inside the same conversation. Our escalation guide covers when to hand off and how to do it without losing context. Your admin still needs to allow the app - section 6 applies to every Teams app ever published - but everything below that line is taken care of.
Start free with Conferbot - no credit card required.
Debugging right now? Open Test in Web Chat on the Azure Bot resource. Whether it answers decides which half of this guide you need.
Was this article helpful?
Build and deploy in 10 minutes. No coding needed.
Microsoft Teams Bot Not Responding? Manifest, 401s, Policies and 7 More FAQ
Everything you need to know about chatbots for microsoft teams bot not responding? manifest, 401s, policies and 7 more.
About the Author
The Conferbot team writes about building, deploying, and improving AI chatbots.
View all articlesRelated Articles
From the reference shelf
Fact-checked reference pages and free tools for the platform this article covers.