Skip to content
🎉 Launch sale:50% off everything over $22 — automatically applied at checkout· ends Aug 2Shop the sale →
DevOps AI ToolKit
Newsletter
All guides
AI for Microsoft Teams By James Joyner IV · · 8 min read Last reviewed Jul 2026

Microsoft Teams Error: 'Service Unavailable' — Cause, Fix, and Troubleshooting Guide

Quick answer

Fix Microsoft Graph 503 Service Unavailable for Teams: honor Retry-After, exponential backoff with jitter, idempotent retries, and reading service health.

  • #microsoft-teams
  • #troubleshooting
  • #errors
  • #graph-api
Free toolkit

Stuck on this Microsoft Teams error? Get the free incident triage checklist

A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.

What this error means

An HTTP 503 from Microsoft Graph means the service is temporarily unable to handle the request — it is overloaded, or a backend dependency it relies on is momentarily unavailable. This is a transient, server-side condition, not a problem with your request. Graph typically returns the code serviceNotAvailable (and sometimes the generic UnknownError), and often includes a Retry-After header telling you how long to wait before trying again.

HTTP/1.1 503 Service Unavailable
Retry-After: 12
Content-Type: application/json

{
  "error": {
    "code": "serviceNotAvailable",
    "message": "Service is temporarily unavailable. Please try again later.",
    "innerError": {
      "date": "2026-07-12T13:15:02",
      "request-id": "e21b90aa-7744-4c1a-90bb-11ff22aa3355",
      "client-request-id": "e21b90aa-7744-4c1a-90bb-11ff22aa3355"
    }
  }
}

A Graph 503 is distinct from a 502 you might see from the Bot Framework/Bot Service path. A 503 is Graph telling you the service itself is unavailable; treat it as retryable and back off. The right response is almost never to change the request — it is to wait and retry safely.

What users report

  • Graph calls intermittently return HTTP 503 with code serviceNotAvailable or UnknownError.
  • A Retry-After header is present on the 503 response.
  • Failures cluster in time — many requests fail together, then recover together.
  • Retrying the exact same request a few seconds later succeeds unchanged.
  • The Microsoft 365 service health dashboard shows a Teams or Graph advisory during the window.
  • Long-running provisioning jobs fail partway through with no code or config change on your side.

Tenant and app configuration causes

  • Transient service overload. Graph is shedding load and returning 503 until capacity recovers.
  • Backend dependency down. A service Graph depends on is momentarily unavailable, surfaced to you as a 503.
  • Ongoing service incident. An active Microsoft 365/Teams incident is degrading availability tenant-wide.
  • Retry storm amplification. Aggressive, un-jittered client retries pile onto an already-stressed service and prolong the failures.
  • No backoff on your side. The client treats 503 as a hard error or retries immediately, making the situation worse.

Confirming tenant configuration

Capture the status code, Retry-After, and the request identifiers on every failure — you need them for correlation and for any support case:

curl -s -D - -o /tmp/body.json -X GET \
  "https://graph.microsoft.com/v1.0/teams/TEAM_ID/channels" \
  -H "Authorization: Bearer $GRAPH_TOKEN" \
  | awk 'BEGIN{IGNORECASE=1} /^HTTP|^Retry-After:|^request-id:|^client-request-id:|^x-ms-ags-diagnostic:/'

Pull the correlation IDs out of the body as well, since Graph echoes them in innerError:

jq '{code: .error.code, requestId: .error.innerError["request-id"],
     clientRequestId: .error.innerError["client-request-id"]}' /tmp/body.json

Read the Retry-After value programmatically so your client waits the amount the service asked for:

RETRY=$(curl -s -D - -o /dev/null -X GET \
  "https://graph.microsoft.com/v1.0/teams/TEAM_ID/channels" \
  -H "Authorization: Bearer $GRAPH_TOKEN" \
  | awk 'BEGIN{IGNORECASE=1} /^Retry-After:/{print $2}' | tr -d '\r')
echo "service asked us to wait: ${RETRY:-unset} seconds"

When you see clustered 503s, check the Microsoft 365 admin center service health dashboard for an active Teams/Graph incident before assuming the problem is yours.

Resolution

Honor Retry-After first: if the header is present, wait exactly that long before retrying. If it is absent, fall back to exponential backoff with jitter so concurrent clients do not retry in lockstep.

call_with_backoff() {
  local url="$1" attempt=0 max=6
  while :; do
    code=$(curl -s -o /tmp/resp.json -D /tmp/hdr.txt -w '%{http_code}' \
      -H "Authorization: Bearer $GRAPH_TOKEN" "$url")
    if [ "$code" != "503" ]; then cat /tmp/resp.json; return 0; fi

    attempt=$((attempt+1))
    [ "$attempt" -gt "$max" ] && { echo "giving up after $max retries"; return 1; }

    ra=$(awk 'BEGIN{IGNORECASE=1}/^Retry-After:/{print $2}' /tmp/hdr.txt | tr -d '\r')
    if [ -n "$ra" ]; then
      sleep "$ra"
    else
      base=$(( 2 ** attempt )); jitter=$(( RANDOM % (base + 1) ))
      sleep $(( base + jitter ))
    fi
  done
}

call_with_backoff "https://graph.microsoft.com/v1.0/teams/TEAM_ID/channels"

Only retry idempotent operations blindly. For non-idempotent writes (creating a team, posting a message), pair the retry with a client-side dedupe key or a check-then-act so a retry after a 503 does not create a duplicate — the original request may have partially succeeded. Add a circuit breaker so that once you see sustained 503s you stop hammering Graph for a cool-down period and let the service recover, then resume.

Avoiding tenant drift

  • Always honor Retry-After. When the header is present, wait exactly that long — do not retry sooner.
  • Jitter your backoff. Un-jittered retries synchronize clients into a retry storm that prolongs the outage.
  • Cap retries and add a circuit breaker. Bounded retries plus a cool-down stop your fleet from amplifying a service incident.
  • Guard non-idempotent writes. Use dedupe keys or check-then-act so a post-503 retry cannot create duplicates.
  • Log request-id and client-request-id. You cannot correlate with Microsoft support or your own traces without them.
  • Check service health before deep debugging. A tenant-wide incident is not something your code can fix — confirm it first.
Free download · 368-page PDF

Fixed it? Get 500 Microsoft Teams & DevOps AI prompts — free

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.

Did this fix your issue?

Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

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.