Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Microsoft Teams By James Joyner IV · · 11 min read

Microsoft Teams Error Guide: 'Bot: service unavailable / 502' Teams Bot Messaging Endpoint Unreachable

Fix Teams bot 502 Bad Gateway and service unavailable errors: diagnose messaging endpoint connectivity, Bot Framework token issues, and activity delivery failures.

  • #microsoft-teams
  • #troubleshooting
  • #errors
  • #bot-framework

Overview

A 502 Bad Gateway or “Bot: service unavailable” error means the Bot Framework service reached the bot’s registered messaging endpoint URL but received no valid HTTP response — the bot host is down, returned a non-2xx status, took too long to respond (Bot Framework enforces a 15-second timeout), or the TLS handshake failed. From a Teams user’s perspective, the bot appears to hang and then fails with a generic service error.

The Bot Framework Activity delivery failure appears in the Bot Framework portal or as an error activity sent back to the conversation:

HTTP 502 Bad Gateway

{
  "error": {
    "code": "ServiceUnavailable",
    "message": "The bot is currently unavailable. Please try again later."
  }
}

When calling the Bot Framework token endpoint or Connector API directly, the error may surface as:

HTTP 502 Bad Gateway
{
  "statusCode": 502,
  "message": "Bad Gateway: The upstream bot host returned an invalid or no response.",
  "requestId": "a1b2c3d4-1111-2222-3333-444455556666"
}

This error category covers three related failure modes: (1) the bot messaging endpoint (https://your-bot.example.com/api/messages) is unreachable or returning 5xx, (2) the Bot Framework Connector cannot obtain or refresh a bot token from https://amer.token.botframework.com, and (3) a proactive message or messaging extension invocation fails because the bot cannot POST to /v3/conversations/{conversationId}/activities.

Symptoms

  • Teams users send a message or invoke a messaging extension but the bot never responds; Teams eventually shows “Something went wrong”.
  • The Bot Framework Activity log in the Azure portal shows repeated 502 or 408 delivery attempts.
  • Proactive messages from the bot (using the Connector client) fail with ServiceUnavailable.
  • The bot’s /api/messages endpoint returns 502 or times out in browser/curl tests.
  • Token acquisition from amer.token.botframework.com fails intermittently with 502.
curl -s -o /dev/null -w "%{http_code}" \
  -X POST https://your-bot.example.com/api/messages \
  -H "Content-Type: application/json" \
  -d '{"type":"ping"}'
502
curl -s -X POST \
  "https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&client_id=$BOT_APP_ID&client_secret=$BOT_SECRET&scope=https%3A%2F%2Fapi.botframework.com%2F.default" | jq '{access_token: (.access_token // "FAILED"), error}'
{
  "access_token": "FAILED",
  "error": "temporarily_unavailable"
}

Common Root Causes

1. Bot messaging endpoint host is down or returning 5xx

The most common cause: the web server or container hosting the bot has crashed, is restarting, or its health check is failing. The Bot Framework Connector makes an outbound HTTPS POST to the registered endpoint; any non-2xx response is treated as unavailability.

# Check if the bot endpoint is reachable at all
curl -sv --max-time 10 \
  -X POST https://your-bot.example.com/api/messages \
  -H "Content-Type: application/json" \
  -d '{"type":"ping"}' 2>&1 | grep -E "^[<>]|HTTP|connect"
*   Trying 203.0.113.42:443...
* connect to 203.0.113.42 port 443 failed: Connection refused
curl: (7) Failed to connect to your-bot.example.com port 443 after 45 ms: Connection refused

Connection refused means the process is not listening. Check the bot host’s process status and logs.

2. Bot Framework Connector cannot reach the endpoint (firewall / NSG blocking)

The Bot Framework Connector originates from Azure datacenter IP ranges. If the bot host is behind a firewall, cloud security group, or on-premises network that does not allow inbound HTTPS (443) from Azure Bot Service IPs, all activity delivery fails at the network layer.

# Verify TLS from a neutral host
curl -sv --max-time 10 \
  https://your-bot.example.com/api/messages \
  -H "Content-Type: application/json" \
  -d '{}' 2>&1 | grep -E "SSL|TLS|certificate|connect|HTTP"
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* Server certificate: your-bot.example.com
> POST /api/messages HTTP/1.1
< HTTP/1.1 200 OK

If this succeeds from your machine but fails from Azure, the firewall is blocking Bot Framework egress IPs. Allow the Azure Bot Service service tag in your NSG or firewall rules.

3. Bot token acquisition from amer.token.botframework.com failing

The bot must obtain a token from https://amer.token.botframework.com (or the Europe/Asia equivalents) to authenticate outbound calls to the Bot Framework Connector. If this endpoint is unreachable or the bot’s app ID / secret are wrong, outbound proactive messages and replies fail with 502 at the Connector layer.

# Test token acquisition directly
curl -s -X POST \
  "https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&client_id=$BOT_APP_ID&client_secret=$BOT_SECRET&scope=https%3A%2F%2Fapi.botframework.com%2F.default" | jq '{token_type, expires_in, error, error_description}'
{
  "token_type": null,
  "expires_in": null,
  "error": "invalid_client",
  "error_description": "AADSTS70011: The provided request must include a 'client_secret' input parameter."
}

invalid_client or AADSTS errors mean the bot’s MicrosoftAppId / MicrosoftAppPassword in its configuration do not match the registered Azure AD app credentials.

4. Bot response exceeds the 15-second timeout

The Bot Framework Connector waits 15 seconds for the bot to return HTTP 200 (or any 2xx). If the bot’s OnMessageActivityAsync or equivalent handler blocks on a slow database call, downstream API, or LLM completion, the Connector marks the delivery as failed and the user sees the service error. The bot’s own logs show the handler completing successfully — but too late.

# Measure bot endpoint response time
time curl -s -X POST https://your-bot.example.com/api/messages \
  -H "Authorization: Bearer $BOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "message",
    "id": "test-activity-001",
    "serviceUrl": "https://smba.trafficmanager.net/amer/",
    "from": {"id": "test-user"},
    "conversation": {"id": "test-conv"},
    "recipient": {"id": "'$BOT_APP_ID'"},
    "text": "ping"
  }'
real    0m16.423s

Response time over 15 seconds confirms a timeout. The bot must acknowledge the activity (return 200) immediately and send the reply asynchronously via /v3/conversations/{id}/activities.

5. Invalid or expired TLS certificate on the bot endpoint

The Bot Framework Connector validates the bot endpoint’s TLS certificate. Self-signed certificates, expired certificates, or certificates missing the intermediate chain cause the TLS handshake to fail, resulting in 502 at the Connector.

# Check certificate expiry and chain
curl -sv --max-time 10 https://your-bot.example.com/api/messages 2>&1 | \
  grep -E "expire|issuer|subject|SSL|verify"
*  subject: CN=your-bot.example.com
*  start date: Jan 15 00:00:00 2026 GMT
*  expire date: Jun 10 00:00:00 2026 GMT
*  SSL certificate verify result: certificate has expired (10), continuing anyway.

An expired certificate (expire date in the past) means every Bot Framework delivery attempt fails at TLS. Renew the certificate immediately.

6. Proactive message POST to /v3/conversations fails because serviceUrl is incorrect

When the bot sends a proactive message, it must POST to the correct regional serviceUrl that was captured from the original inbound activity (e.g., https://smba.trafficmanager.net/amer/). Using a hardcoded or wrong serviceUrl routes the request to the wrong datacenter shard, returning 502 or 404.

# Attempt a proactive message with a correct serviceUrl and bot token
curl -s -X POST \
  "https://smba.trafficmanager.net/amer/v3/conversations/$CONVERSATION_ID/activities" \
  -H "Authorization: Bearer $BOT_CONNECTOR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "message",
    "from": {"id": "'$BOT_APP_ID'", "name": "MyBot"},
    "text": "Proactive alert: deployment complete."
  }' | jq '{id, error}'
{
  "id": null,
  "error": {
    "code": "ServiceUnavailable",
    "message": "The specified conversation was not found on this datacenter shard."
  }
}

The serviceUrl must be stored from the original Activity.ServiceUrl when the bot first joined the conversation — never derived or guessed.

Diagnostic Workflow

Step 1: Verify the bot endpoint responds to HTTP from your network

curl -sv --max-time 20 \
  -X POST https://your-bot.example.com/api/messages \
  -H "Content-Type: application/json" \
  -d '{"type":"ping"}' 2>&1 | tail -20

Any connection error (refused, timeout, TLS failure) means the host-level problem must be resolved before investigating Bot Framework configuration.

Step 2: Check TLS certificate validity

echo | openssl s_client -connect your-bot.example.com:443 -servername your-bot.example.com 2>/dev/null | \
  openssl x509 -noout -dates -issuer -subject

Confirm notAfter is in the future and the issuer is a public CA trusted by Azure (not self-signed).

Step 3: Test Bot Framework token acquisition

curl -s -X POST \
  "https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&client_id=$BOT_APP_ID&client_secret=$BOT_SECRET&scope=https%3A%2F%2Fapi.botframework.com%2F.default" | jq '{token_type, expires_in, error}'

A successful response returns "token_type": "Bearer" and a positive expires_in. Any error field means the credentials or tenant registration is wrong.

Step 4: Check the Azure Bot Service Activity log

In the Azure portal, navigate to your Bot Service resource → Test in Web Chat → send a message → then check Activity logs for delivery status. Alternatively use the Bot Framework Emulator to send a test activity directly to the endpoint and observe the raw HTTP exchange.

# Check Azure resource health for the Bot Service
az bot show --resource-group $RG --name $BOT_NAME \
  --query "{endpoint:properties.endpoint, state:properties.msaAppId}" -o table
Endpoint                                         State
-----------------------------------------------  ------------------------------------
https://your-bot.example.com/api/messages        a1b2c3d4-1111-2222-3333-444455556666

Verify the endpoint matches what is actually deployed.

Step 5: Measure handler response time and check bot host logs

# Time a realistic activity POST
time curl -s -X POST https://your-bot.example.com/api/messages \
  -H "Authorization: Bearer $BOT_CONNECTOR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "message",
    "serviceUrl": "https://smba.trafficmanager.net/amer/",
    "from": {"id": "test-user-id"},
    "conversation": {"id": "test-conv-id"},
    "recipient": {"id": "'$BOT_APP_ID'"},
    "text": "hello"
  }'

# Check bot host logs (systemd example)
sudo journalctl -u your-bot-service --no-pager --since "15 minutes ago" | tail -40

If wall time exceeds 15 seconds, the handler is too slow and must be made asynchronous.

Example Root Cause Analysis

A Teams bot that posts deployment alerts to a channel stops responding after a certificate renewal was skipped during a maintenance freeze. Users invoke the messaging extension and get “Something went wrong.”

Checking the endpoint directly:

curl -sv https://your-bot.example.com/api/messages 2>&1 | grep -i expire
*  expire date: Jun 10 00:00:00 2026 GMT
*  SSL certificate verify result: certificate has expired (10)

The certificate expired on 10 June. Let’s Encrypt auto-renewal had been disabled when the host was moved to a new VM and the systemd timer was not re-enabled.

Fix: renew the certificate and re-enable the renewal timer:

sudo certbot renew --force-renewal --cert-name your-bot.example.com
sudo systemctl enable --now certbot.timer

# Verify new expiry
echo | openssl s_client -connect your-bot.example.com:443 2>/dev/null | \
  openssl x509 -noout -dates
notBefore=Jun 23 00:00:00 2026 GMT
notAfter=Sep 21 00:00:00 2026 GMT

After the certificate is renewed, the Bot Framework Connector completes the TLS handshake, activities deliver successfully, and the messaging extension returns results within two seconds.

Prevention Best Practices

  • Monitor the bot messaging endpoint with an external uptime check (HTTP POST to /api/messages with a {"type":"ping"} payload) and alert on non-2xx or response time over 10 seconds — giving a 5-second buffer before the Bot Framework 15-second timeout triggers.
  • Automate TLS certificate renewal (certbot systemd timer, Azure App Service managed certs) and alert at 30 days before expiry; Bot Framework TLS validation is strict and allows no grace period.
  • Store the serviceUrl from inbound activities in a durable store (database, Azure Table Storage) keyed by conversation.id and always use the stored value for proactive messages — never hardcode a regional URL.
  • Implement the “immediate 202 + async reply” pattern in all bot handlers: return HTTP 202 within one second, then post the reply to /v3/conversations/{id}/activities using the Connector client asynchronously to avoid the 15-second timeout on slow operations.
  • Restrict inbound 443 on the bot host to the Azure Bot Service IP ranges or service tag rather than opening to all sources — reduces attack surface without blocking Bot Framework delivery.
  • Route bot 502 and delivery failure alerts through the incident assistant to correlate certificate expiry, upstream outage, and host status in a single triage view.

Quick Command Reference

# Check bot endpoint reachability and HTTP status
curl -s -o /dev/null -w "%{http_code}\n" --max-time 10 \
  -X POST https://your-bot.example.com/api/messages \
  -H "Content-Type: application/json" -d '{"type":"ping"}'

# Check TLS certificate expiry
echo | openssl s_client -connect your-bot.example.com:443 -servername your-bot.example.com 2>/dev/null | \
  openssl x509 -noout -dates -subject -issuer

# Acquire a Bot Framework Connector token
curl -s -X POST \
  "https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&client_id=$BOT_APP_ID&client_secret=$BOT_SECRET&scope=https%3A%2F%2Fapi.botframework.com%2F.default" | jq .

# Send a proactive message via Bot Framework Connector
curl -s -X POST \
  "https://smba.trafficmanager.net/amer/v3/conversations/$CONVERSATION_ID/activities" \
  -H "Authorization: Bearer $BOT_CONNECTOR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"type":"message","from":{"id":"'$BOT_APP_ID'","name":"MyBot"},"text":"Proactive test."}' | jq .

# Measure handler response time
time curl -s -X POST https://your-bot.example.com/api/messages \
  -H "Authorization: Bearer $BOT_CONNECTOR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"type":"message","serviceUrl":"https://smba.trafficmanager.net/amer/","from":{"id":"u1"},"conversation":{"id":"c1"},"recipient":{"id":"'$BOT_APP_ID'"},"text":"timing test"}'

# Check Azure Bot Service registration endpoint
az bot show --resource-group $RG --name $BOT_NAME \
  --query "properties.endpoint" -o tsv

# Renew Let's Encrypt certificate
sudo certbot renew --force-renewal --cert-name your-bot.example.com

Conclusion

A Teams bot 502 / “service unavailable” error means the Bot Framework Connector reached the registered messaging endpoint but could not get a valid response. The six root causes in order of likelihood:

  1. The bot host process is down, restarting, or returning 5xx — the most common cause; check the host process status and application logs first.
  2. A firewall or NSG is blocking inbound HTTPS from Azure Bot Service IP ranges to the bot host.
  3. Bot Framework token acquisition from amer.token.botframework.com is failing due to incorrect MicrosoftAppId / MicrosoftAppPassword credentials.
  4. The bot’s activity handler takes longer than 15 seconds to return HTTP 200 — implement the immediate-acknowledge-then-async-reply pattern.
  5. The TLS certificate on the bot endpoint is expired or self-signed — Bot Framework validates the full chain against public trust stores.
  6. A proactive message targets the wrong serviceUrl — always use the value captured from the original inbound activity, never a hardcoded regional URL.

Start by hitting the bot endpoint directly with curl to isolate host-level failures before investigating Bot Framework configuration or token issues. See more troubleshooting patterns in Microsoft Teams guides.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.