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
- User uploads a file in a Teams channel
- Bot Framework delivers the activity with
contentType: "text/html" attachment (HTML card)
downloadMSTeamsAttachments returns empty (expected — HTML cards are not directly downloadable)
- Plugin enters Graph API fallback path (
onlyHtmlAttachments = true)
buildMSTeamsGraphMessageUrls builds correct URL (verified)
downloadMSTeamsGraphMedia returns { media: [] } — this is the bug
- 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:
- MSAL token acquisition —
MsalTokenProvider.getAccessToken("https://graph.microsoft.com") returns valid token ( chars)
- Graph message fetch —
GET /teams/{teamId}/channels/{channelId}/messages/{messageId} returns 200 with attachments[0].contentType: "reference" and valid SharePoint contentUrl
- SharePoint download via shares API —
GET /shares/u!{base64url}/driveItem/content returns 200, downloads full PDF ( bytes)
- SSRF guard —
fetchWithSsrFGuard with the same policy passes for graph.microsoft.com (returns 401 with fake token, not blocked)
- 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
- Add error logging inside the catch blocks (at minimum log the error message)
- Include the
attempts array data in the graph media fetch empty log output
- 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.
Summary
MS Teams channel file attachments (PDFs, documents) are never delivered to the agent. The plugin logs
graph media fetch emptyon every inbound file, despite all Graph API permissions being correctly configured and working when tested manually.Environment
Symptoms
contentType: "text/html"attachment (HTML card)downloadMSTeamsAttachmentsreturns empty (expected — HTML cards are not directly downloadable)onlyHtmlAttachments = true)buildMSTeamsGraphMessageUrlsbuilds correct URL (verified)downloadMSTeamsGraphMediareturns{ media: [] }— this is the bugWhat works (tested manually from inside the container)
All of these succeed when called directly with the same credentials:
MsalTokenProvider.getAccessToken("https://graph.microsoft.com")returns valid token ( chars)GET /teams/{teamId}/channels/{channelId}/messages/{messageId}returns 200 withattachments[0].contentType: "reference"and valid SharePointcontentUrlGET /shares/u!{base64url}/driveItem/contentreturns 200, downloads full PDF ( bytes)fetchWithSsrFGuardwith the same policy passes forgraph.microsoft.com(returns 401 with fake token, not blocked)Graph API Permissions (all granted with admin consent)
Application:
ChannelMessage.Read.AllChatMessage.Read.AllChat.Read.AllFiles.Read.AllGroup.Read.AllSites.ReadWrite.AllDelegated:
Chat.ReadWriteChannelMessage.ReadWrite.AllFiles.ReadWrite.AllUser.ReadConfiguration
{ "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
graph media fetch emptylog does not include the{ attempts }metadata in the structured log output, making it hard to see HTTP status codessharePointSiteId<redacted-msg-id>)Likely cause
Something in the
downloadMSTeamsGraphMediafunction silently fails between the token acquisition and the final media result. The outertry/catchblocks ingraph.ts(lines ~263 and ~333) swallow all errors: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
attemptsarray data in thegraph media fetch emptylog outputdebuglog before and after the SharePoint attachment extraction loopWorkaround
None found. Users can paste URLs instead of uploading files as a temporary workaround.