fix(bluebubbles): route fetchImpl through bundled undici fetch on Node 24+#66108
fix(bluebubbles): route fetchImpl through bundled undici fetch on Node 24+#66108coletebou wants to merge 1 commit intoopenclaw:mainfrom
Conversation
…hment downloads on Node 24+ The SSRF guard pinned-DNS dispatcher is an undici 8.x Agent, but Node 24 built-in globalThis.fetch uses undici 7.x internally. Passing the 8.x dispatcher to native fetch causes 'invalid onRequestStart method' errors, breaking all BlueBubbles attachment downloads. Route through fetchWithRuntimeDispatcher (bundled undici own fetch) when a dispatcher is present, matching the Slack extension (openclaw#62239). Preserves SSRF DNS pinning, forwards opts.timeoutMs via AbortSignal.timeout (default 10s), and honours test-installed globalThis.fetch mocks via isMockedFetch guard.
Greptile SummaryFixes attachment download failures on Node 24+ by routing the Confidence Score: 5/5Safe to merge — the fix is a targeted, well-precedented compatibility patch with no P0/P1 issues. The dispatcher-routing logic exactly mirrors the Slack and Matrix extensions, No files require special attention. Prompt To Fix All With AIThis is a comment left during a code review.
Path: extensions/bluebubbles/src/attachments.ts
Line: 97-102
Comment:
**Duplicated `isMockedFetch` helper — third copy in the codebase**
An identical implementation already lives in `extensions/slack/src/monitor/media.ts:66-70` and `extensions/matrix/src/matrix/sdk/transport.ts:94-98`. The function is not currently exported from `openclaw/plugin-sdk/infra-runtime` (the SDK re-exports `fetchWithRuntimeDispatcher` from `fetch-guard`, but `isMockedFetch` is only exported from `runtime-fetch.ts` without a re-export). If this pattern is needed by a fourth extension, consider promoting `isMockedFetch` to the SDK instead of another copy. No action required to merge — the local copy is safe and consistent with the Slack/Matrix approach.
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "fix(bluebubbles): route fetchImpl throug..." | Re-trigger Greptile |
| function isMockedFetch(fetchImpl: typeof fetch | undefined): boolean { | ||
| if (typeof fetchImpl !== "function") { | ||
| return false; | ||
| } | ||
| return typeof (fetchImpl as typeof fetch & { mock?: unknown }).mock === "object"; | ||
| } |
There was a problem hiding this comment.
Duplicated
isMockedFetch helper — third copy in the codebase
An identical implementation already lives in extensions/slack/src/monitor/media.ts:66-70 and extensions/matrix/src/matrix/sdk/transport.ts:94-98. The function is not currently exported from openclaw/plugin-sdk/infra-runtime (the SDK re-exports fetchWithRuntimeDispatcher from fetch-guard, but isMockedFetch is only exported from runtime-fetch.ts without a re-export). If this pattern is needed by a fourth extension, consider promoting isMockedFetch to the SDK instead of another copy. No action required to merge — the local copy is safe and consistent with the Slack/Matrix approach.
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/bluebubbles/src/attachments.ts
Line: 97-102
Comment:
**Duplicated `isMockedFetch` helper — third copy in the codebase**
An identical implementation already lives in `extensions/slack/src/monitor/media.ts:66-70` and `extensions/matrix/src/matrix/sdk/transport.ts:94-98`. The function is not currently exported from `openclaw/plugin-sdk/infra-runtime` (the SDK re-exports `fetchWithRuntimeDispatcher` from `fetch-guard`, but `isMockedFetch` is only exported from `runtime-fetch.ts` without a re-export). If this pattern is needed by a fourth extension, consider promoting `isMockedFetch` to the SDK instead of another copy. No action required to merge — the local copy is safe and consistent with the Slack/Matrix approach.
How can I resolve this? If you propose a fix, please make it concise.|
Superseded by #67510 (merged 2026-04-16). Your diagnosis of the bundled-undici dispatcher breakage on modern Node was on target; #67510's fix #1 takes a different approach (strip the dispatcher from the non-SSRF fallback path in |
Summary
BlueBubbles attachment downloads fail on Node 24+ because the SSRF guard's pinned-DNS dispatcher is an undici 8.x
Agent, but Node 24's built-inglobalThis.fetchuses undici 7.x internally. Passing the 8.x dispatcher causes"invalid onRequestStart method"errors.Routes through
fetchWithRuntimeDispatcher(bundled undici's own fetch) when a dispatcher is present ininit, matching the approach used by the Slack extension (#62239).Supersedes #66103 and #63984.
Changes
extensions/bluebubbles/src/attachments.ts:fetchWithRuntimeDispatcherwheninitcontains adispatcher(preserves SSRF DNS pinning)isMockedFetchguard so test-installedglobalThis.fetchmocks are honoured (parity with Slack)opts.timeoutMs(default 10s) viaAbortSignal.timeout— no timeout regressionblueBubblesFetchWithTimeoutimportTest plan
timeoutMs)