Skip to content

Teams: SharePoint file download fails on Node 24+ due to undici strict dispatcher incompatibility #63396

@EdgarSPHBot

Description

@EdgarSPHBot

Description

Teams file attachments (documents, images sent in DMs) fail to download silently on Node 24+ (tested on v24.13.1, v25.7.0, v25.8.1, v25.8.2). The Graph API message fetch succeeds, SharePoint reference attachments are visible in the response, but the actual file content download via /shares/u!.../driveItem/content fails with:

MediaFetchError: Failed to fetch media from .../driveItem/content: fetch failed | invalid onRequestStart method
cause: TypeError: fetch failed

The error is swallowed by an empty catch {} in the SharePoint download loop, resulting in "graph media fetch empty" at debug level with no indication of the root cause.

Root Cause

fetchRemoteMedia in fetch-BgzO65-j.js always uses withStrictGuardedFetchMode, which triggers createPinnedDispatcher in ssrf-8K2hYwIJ.js. The pinned dispatcher creates an undici.Agent with a custom connect.lookup for DNS pinning. On Node 24+ (which ships undici v7), the dispatcher handler API changed — the onRequestStart method signature is incompatible, causing an immediate TypeError: fetch failed before any network request is made.

This does NOT affect the Graph message fetch (which uses fetchWithSsrFGuard in non-strict mode via safeFetchWithPolicy), only the fetchRemoteMedia path used for downloading file content.

Impact

  • All Teams DM file attachments (documents, PDFs, images sent as files) silently fail
  • The <media:document> tag appears in the agent's input but no file content is delivered
  • No visible error at INFO log level — only discoverable via debug logging or code instrumentation

Reproduction

  1. Run OpenClaw on Node 24+ with Teams configured
  2. Send a file attachment in a Teams DM to the bot
  3. The agent receives <media:document> but no file content
  4. Debug logs show "graph media fetch empty"

Workaround

Bypass fetchRemoteMedia in downloadAndStoreMSTeamsRemoteMedia by replacing the fetchRemoteMedia call with a direct fetch using the existing custom fetchImpl (which already handles auth headers and allowlist validation via safeFetchWithPolicy):

// In downloadAndStoreMSTeamsRemoteMedia, replace:
const fetched = await getMSTeamsRuntime().channel.media.fetchRemoteMedia({
    url: params.url,
    fetchImpl: params.fetchImpl,
    filePathHint: params.filePathHint,
    maxBytes: params.maxBytes,
    ssrfPolicy: params.ssrfPolicy
});

// With:
let fetched;
const fetchFn = params.fetchImpl || fetch;
const res = await fetchFn(params.url, { redirect: "follow" });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const buffer = Buffer.from(await res.arrayBuffer());
if (params.maxBytes && buffer.byteLength > params.maxBytes) throw new Error("File too large");
fetched = { buffer, contentType: res.headers.get("content-type") || "application/octet-stream" };

The URL has already been validated by isUrlAllowed() before reaching downloadAndStoreMSTeamsRemoteMedia, so skipping the strict SSRF dispatcher is safe for this code path.

Additional Note

Teams file attachments also require Files.Read.All (Application) permission on the Azure bot app registration — without it, the Graph sharing API returns 403. This is not documented in the OpenClaw Teams setup guide. The Chat.Read.All and ChatMessage.Read.All permissions are insufficient for downloading file content.

Related

Environment

  • OpenClaw: 2026.4.5, 2026.4.8
  • Node: v24.13.1, v25.7.0, v25.8.1, v25.8.2
  • Platform: Ubuntu 24.04, macOS
  • Channel: Microsoft Teams (personal DMs)

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