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 · · 9 min read Last reviewed Jul 2026

Microsoft Teams Error Guide: 'This card couldn't be displayed' — Adaptive Card Render Failures

Quick answer

Fix 'This card couldn't be displayed' in Microsoft Teams: pin the schema version Teams supports, add element fallback, wrap payloads correctly, and stay under the card size limit.

  • #microsoft-teams
  • #adaptive-cards
  • #troubleshooting
  • #errors
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.

Overview

An Adaptive Card that posts successfully but renders as a grey placeholder is one of the most confusing Teams failures: the HTTP call returned 200/202, yet the recipient sees no card content. Teams renders this fallback text in the message body:

This card couldn't be displayed. [Please update Teams / open in browser]

In bot scenarios the underlying activity may also surface a Bot Framework error before it ever reaches the client:

{
  "error": {
    "code": "BadRequest",
    "message": "Invalid Card: the card version '1.6' is not supported by this host."
  }
}

The root problem is almost always a mismatch between the Adaptive Card you sent and what the specific Teams host can render — a schema version set too high, an element the host does not support with no fallback, an invalid card body, or a payload that is not wrapped the way the channel expects.

Symptoms

  • The message posts (HTTP 200/201/202) but the card area shows “This card couldn’t be displayed.”
  • The card renders on Teams desktop but is blank on mobile, or vice versa.
  • The card renders in the Adaptive Cards Designer but fails inside Teams.
  • A bot log shows Invalid Card / BadRequest when calling POST /v3/conversations/{id}/activities.
  • An incoming Workflows webhook returns HTTP 400 or posts an empty card.
  • The whole card blanks even though only one new element (a Table, Input, or Action.Execute) is unsupported.

Common Root Causes

1. Schema version set higher than the host supports

Teams does not render the newest Adaptive Cards schema. Each host caps at a specific version, and setting "version" above that makes the entire card fail closed — nothing renders.

{
  "type": "AdaptiveCard",
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "version": "1.6",
  "body": [
    { "type": "TextBlock", "text": "Deploy succeeded" }
  ]
}

Modern Teams clients support up to Adaptive Cards 1.5. A card declaring 1.6 is rejected wholesale. Pin version to 1.5 (or lower for Outlook Actionable Messages).

2. An unsupported element with no fallback

If a card uses an element or action that requires a newer version than the host supports and provides no fallback, the host drops the entire card, not just that element.

{
  "type": "Table",
  "columns": [ { "width": 1 }, { "width": 1 } ],
  "rows": []
}

Table requires 1.5. On a 1.4 host with no fallback, the card blanks. Add element-level fallback so only that element degrades:

{
  "type": "Table",
  "columns": [ { "width": 1 }, { "width": 1 } ],
  "rows": [],
  "fallback": {
    "type": "TextBlock",
    "text": "Table view requires a newer Teams client.",
    "wrap": true
  }
}

3. Payload not wrapped in the message envelope (webhooks)

The Power Automate Workflows inbound webhook and the Bot Framework both expect the card inside an attachment envelope, not a bare Adaptive Card. Posting the raw card returns 400 or a blank message.

{
  "type": "message",
  "attachments": [
    {
      "contentType": "application/vnd.microsoft.card.adaptive",
      "content": { "type": "AdaptiveCard", "version": "1.5", "body": [] }
    }
  ]
}

4. Invalid card JSON or wrong contentType

A trailing comma, a missing type on an element, or contentType: "application/vnd.microsoft.card.hero" on Adaptive Card content all produce a render failure. The card must be valid JSON and the contentType must be application/vnd.microsoft.card.adaptive.

5. Card exceeds the size limit

Teams caps a single Adaptive Card payload at roughly 28 KB. Cards that inline large log dumps, big images as base64, or hundreds of rows exceed the limit and fail to render. Truncate content and link out to a dashboard instead of inlining.

6. Templating that produced empty or malformed output

When using Adaptive Card Templating (${...} bindings), an unbound expression or a null data field can emit undefined, a broken structure, or an empty body, all of which render as the fallback placeholder.

Diagnostic Workflow

Step 1: Validate the JSON and the version

echo "$CARD" | jq empty && echo "JSON valid" || echo "JSON INVALID"
echo "$CARD" | jq -r '.version // .attachments[0].content.version'

If version is above 1.5, that alone explains a total render failure on Teams.

Step 2: Confirm the wrapper for webhook posts

Test the Workflows inbound webhook with a correctly wrapped, minimal card and check the HTTP status:

curl -s -o /dev/null -w "%{http_code}\n" -X POST "$WORKFLOW_URL" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "message",
    "attachments": [
      {
        "contentType": "application/vnd.microsoft.card.adaptive",
        "content": {
          "type": "AdaptiveCard",
          "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
          "version": "1.5",
          "body": [ { "type": "TextBlock", "text": "render test", "wrap": true } ]
        }
      }
    ]
  }'

202 means the payload shape is accepted. If a bare card returned 400 but the wrapped one returns 202, the missing envelope was the cause.

Step 3: Check the payload size

echo "$CARD" | wc -c

Anything approaching 28000 bytes is at risk. Trim inlined content.

Step 4: Bisect elements to find the unsupported one

Post the card with only a TextBlock, confirm it renders, then add elements back one at a time. The element that blanks the card is the one that needs fallback or a lower version.

# Minimal known-good card
curl -s -o /dev/null -w "%{http_code}\n" -X POST "$WORKFLOW_URL" \
  -H "Content-Type: application/json" \
  -d '{"type":"message","attachments":[{"contentType":"application/vnd.microsoft.card.adaptive","content":{"type":"AdaptiveCard","version":"1.5","body":[{"type":"TextBlock","text":"ok"}]}}]}'

Step 5: Reproduce in the Designer with the Teams host config

Open https://adaptivecards.io/designer, select the Microsoft Teams host config, and paste the card. The Designer flags unsupported elements and version mismatches inline, matching what Teams enforces.

Example Root Cause Analysis

A deployment pipeline posts a summary card containing a Table of the last ten releases. The card renders fine on the engineer’s desktop client during testing but shows “This card couldn’t be displayed” for half the channel — specifically teammates on older mobile clients.

Inspecting the card:

echo "$CARD" | jq '{version, hasTable: (.body[] | select(.type=="Table")) != null}'
{
  "version": "1.5",
  "hasTable": true
}

The card correctly declares 1.5, but the affected mobile clients had not yet updated to a build that renders Table, and there was no fallback, so the entire card blanked for them. The fix adds an element-level fallback so older clients drop only the table and still see the summary and buttons:

{
  "type": "Table",
  "columns": [ { "width": 1 }, { "width": 2 }, { "width": 1 } ],
  "rows": [],
  "fallback": {
    "type": "TextBlock",
    "text": "Open the dashboard to view the release table.",
    "wrap": true
  }
}

A top-level fallbackText was also added so notification previews and the oldest clients show a meaningful line instead of a blank placeholder. After redeploying, every client rendered at least the summary; modern clients rendered the full table.

Prevention Best Practices

  • Pin version to the highest version Teams actually supports (currently 1.5), never to the latest published schema — a too-high version fails the whole card closed.
  • Add element-level fallback (or "fallback": "drop") to every element or action that requires a newer version than your floor, so one unsupported element never blanks the card.
  • Always include a top-level fallbackText so hosts that cannot render the card at all still show useful text.
  • Validate card JSON with jq empty in CI and render-test in the Adaptive Cards Designer with the Teams host config before shipping.
  • Keep cards well under the ~28 KB limit — truncate logs, avoid base64 images, and link out to dashboards instead of inlining large content.
  • For webhook and bot posts, always wrap the card in the {"type":"message","attachments":[...]} envelope with contentType: application/vnd.microsoft.card.adaptive.
  • Cross-reference render failures against the Microsoft Teams guides and the incident assistant to match symptoms to root cause quickly.

Quick Command Reference

# Validate card JSON
echo "$CARD" | jq empty && echo valid || echo INVALID

# Show declared schema version
echo "$CARD" | jq -r '.version // .attachments[0].content.version'

# Check payload size (limit ~28 KB)
echo "$CARD" | wc -c

# Post a minimal wrapped card to a Workflows webhook and print status
curl -s -o /dev/null -w "%{http_code}\n" -X POST "$WORKFLOW_URL" \
  -H "Content-Type: application/json" \
  -d '{"type":"message","attachments":[{"contentType":"application/vnd.microsoft.card.adaptive","content":{"type":"AdaptiveCard","version":"1.5","body":[{"type":"TextBlock","text":"ok"}]}}]}'

# Extract all element types to spot version-gated elements (Table, Input.*, ActionSet)
echo "$CARD" | jq '[.. | .type? // empty] | unique'

Conclusion

“This card couldn’t be displayed” is a rendering contract failure, not an auth or permission problem. In order of frequency the causes are:

  1. version set higher than the Teams host supports, failing the whole card closed.
  2. An unsupported element (Table, newer Input, Action.Execute) with no fallback, blanking the entire card.
  3. The card posted without the {"type":"message","attachments":[...]} envelope on a webhook or bot.
  4. Invalid card JSON or the wrong contentType.
  5. A payload exceeding the ~28 KB card size limit.
  6. Templating that emitted empty or malformed output.

The fastest fix path is: validate the JSON, pin version to 1.5, add fallback plus fallbackText, confirm the message envelope, and render-test in the Adaptive Cards Designer with the Teams host config before shipping.

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.