Skip to content

MS Teams: graph media fetch empty for channel file attachments despite valid permissions and token #51749

@staroscott

Description

@staroscott

Summary

MS Teams channel file attachments (PDFs, documents) are never delivered to the agent. The plugin logs graph media fetch empty on every inbound file, despite all Graph API permissions being correctly configured and working when tested manually.

Environment

  • OpenClaw: 2026.3.13 (Docker)
  • Node: 24.14.0
  • Bot Framework SDK: @microsoft/agents-hosting 1.4.1
  • Conversation type: channel (Teams team)

Symptoms

  1. User uploads a file in a Teams channel
  2. Bot Framework delivers the activity with contentType: "text/html" attachment (HTML card)
  3. downloadMSTeamsAttachments returns empty (expected — HTML cards are not directly downloadable)
  4. Plugin enters Graph API fallback path (onlyHtmlAttachments = true)
  5. buildMSTeamsGraphMessageUrls builds correct URL (verified)
  6. downloadMSTeamsGraphMedia returns { media: [] }this is the bug
  7. Agent receives message text but no file content

What works (tested manually from inside the container)

All of these succeed when called directly with the same credentials:

  1. MSAL token acquisitionMsalTokenProvider.getAccessToken("https://graph.microsoft.com") returns valid token ( chars)
  2. Graph message fetchGET /teams/{teamId}/channels/{channelId}/messages/{messageId} returns 200 with attachments[0].contentType: "reference" and valid SharePoint contentUrl
  3. SharePoint download via shares APIGET /shares/u!{base64url}/driveItem/content returns 200, downloads full PDF ( bytes)
  4. SSRF guardfetchWithSsrFGuard with the same policy passes for graph.microsoft.com (returns 401 with fake token, not blocked)
  5. isUrlAllowed — SharePoint URL passes allowlist check

Graph API Permissions (all granted with admin consent)

Application:

  • ChannelMessage.Read.All
  • ChatMessage.Read.All
  • Chat.Read.All
  • Files.Read.All
  • Group.Read.All
  • Sites.ReadWrite.All

Delegated:

  • Chat.ReadWrite
  • ChannelMessage.ReadWrite.All
  • Files.ReadWrite.All
  • User.Read

Configuration

{
  "mediaAllowHosts": ["*.sharepoint.com", "*.microsoft.com", "*.teams.microsoft.com", "*.graph.microsoft.com", "graph.microsoft.com"],
  "mediaAuthAllowHosts": ["*.sharepoint.com", "*.graph.microsoft.com", "graph.microsoft.com"],
  "sharePointSiteId": "<redacted-sharepoint-site-id>"
}

Also tested with ["*"] for both allowHosts — same result.

Key observations

  • The graph media fetch empty log does not include the { attempts } metadata in the structured log output, making it hard to see HTTP status codes
  • The entire graph fallback path completes in ~400ms (receive → empty result), which is consistent with a token + fetch actually happening
  • File sending via SharePoint works correctly after configuring sharePointSiteId
  • The issue affects both DM and channel file attachments
  • Bot Framework activity.id matches Graph message ID (e.g., <redacted-msg-id>)

Likely cause

Something in the downloadMSTeamsGraphMedia function silently fails between the token acquisition and the final media result. The outer try/catch blocks in graph.ts (lines ~263 and ~333) swallow all errors:

} catch {
  // Ignore message fetch failures.
}
} catch {
  // Ignore SharePoint download failures.
}

This makes it impossible to diagnose whether the Graph message fetch fails, the SharePoint URL filtering rejects the attachment, or the shares API download fails.

Suggested fix

  1. Add error logging inside the catch blocks (at minimum log the error message)
  2. Include the attempts array data in the graph media fetch empty log output
  3. Consider adding a debug log before and after the SharePoint attachment extraction loop

Workaround

None found. Users can paste URLs instead of uploading files as a temporary workaround.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions