Summary
When a user sends an image (inline paste/screenshot) or file attachment via Teams personal DM, the bot receives a msteams://media/... placeholder that is never resolved. The attachment content is silently dropped — no error is shown to the user and no meaningful log is emitted.
Environment
- OpenClaw version:
2026.4.10
- Channel:
msteams (personal DM / personal scope)
- Manifest:
supportsFiles: true, scopes include personal ✅
- Graph API permissions: not configured (RSC only)
Steps to Reproduce
- Configure OpenClaw with msteams (RSC only, no Graph API)
- Open a personal DM with the bot in Teams
- Send an image by pasting/screenshot (inline) OR attach a file via the paperclip button
- Bot receives message but cannot access the attachment content
Expected Behavior
Docs state:
DMs: Images and file attachments work via Teams bot file APIs.
With Teams RSC only: Receive personal (DM) file attachments ✅
Attachment should be downloaded and passed to the agent.
Actual Behavior
Agent receives msteams://media/{messageId}/0 as a placeholder. The image tool rejects it:
Unsupported image reference: msteams://media/1775970156765/0.
Use a file path, a file:// URL, a data: URL, or an http(s) URL.
With logging.level: debug, zero media-related debug logs are emitted — the failure is completely silent.
Root Cause Analysis (code)
In resolveMSTeamsInboundMedia, there are 3 download paths:
Path 1 – Direct URL download (downloadMSTeamsAttachments): Tries contentUrl on the attachment object. Fails silently for inline images in DMs.
Path 2 – Bot Framework attachment download (DM fallback):
if (hasHtmlAttachment && isBotFrameworkPersonalChatId(conversationId))
Only runs when hasHtmlAttachment = true. Inline images sent directly do not include an HTML wrapper, so this condition is never met.
Path 3 – Graph API download (channel/group fallback):
if (hasHtmlAttachment && mediaList.length === 0 && !isBotFrameworkPersonalChatId(conversationId))
Explicitly excluded for personal DMs via !isBotFrameworkPersonalChatId.
Result: all 3 paths fail/skip for inline images in DMs → media dropped silently.
Related
Suggested Fix
For DMs (isBotFrameworkPersonalChatId = true), when Path 1 fails:
- Attempt Bot Framework attachment download regardless of
hasHtmlAttachment (Path 2 without the HTML gate), OR
- Allow Graph API fallback for DMs using the already-resolved
graphConversationId from resolveGraphChatId (Path 3 without !isBotFrameworkPersonalChatId)
Summary
When a user sends an image (inline paste/screenshot) or file attachment via Teams personal DM, the bot receives a
msteams://media/...placeholder that is never resolved. The attachment content is silently dropped — no error is shown to the user and no meaningful log is emitted.Environment
2026.4.10msteams(personal DM / personal scope)supportsFiles: true, scopes includepersonal✅Steps to Reproduce
Expected Behavior
Docs state:
Attachment should be downloaded and passed to the agent.
Actual Behavior
Agent receives
msteams://media/{messageId}/0as a placeholder. Theimagetool rejects it:With
logging.level: debug, zero media-related debug logs are emitted — the failure is completely silent.Root Cause Analysis (code)
In
resolveMSTeamsInboundMedia, there are 3 download paths:Path 1 – Direct URL download (
downloadMSTeamsAttachments): TriescontentUrlon the attachment object. Fails silently for inline images in DMs.Path 2 – Bot Framework attachment download (DM fallback):
Only runs when
hasHtmlAttachment = true. Inline images sent directly do not include an HTML wrapper, so this condition is never met.Path 3 – Graph API download (channel/group fallback):
Explicitly excluded for personal DMs via
!isBotFrameworkPersonalChatId.Result: all 3 paths fail/skip for inline images in DMs → media dropped silently.
Related
!isBotFrameworkPersonalChatId— so DMs still cannot reach it.Suggested Fix
For DMs (
isBotFrameworkPersonalChatId = true), when Path 1 fails:hasHtmlAttachment(Path 2 without the HTML gate), ORgraphConversationIdfromresolveGraphChatId(Path 3 without!isBotFrameworkPersonalChatId)