diff --git a/.changeset/lovely-coins-dream.md b/.changeset/lovely-coins-dream.md new file mode 100644 index 000000000..5abf0c05f --- /dev/null +++ b/.changeset/lovely-coins-dream.md @@ -0,0 +1,6 @@ +--- +'@graphql-tools/executor-http': patch +--- + +Avoid shared AbortController instance on CloudflareWorkers because it gives `Cannot perform I/O on behalf of a different request.` error. +This change ensures that the AbortController is only created when not running in a Cloudflare Workers environment. \ No newline at end of file diff --git a/packages/executors/http/src/index.ts b/packages/executors/http/src/index.ts index 9105def32..7f589734d 100644 --- a/packages/executors/http/src/index.ts +++ b/packages/executors/http/src/index.ts @@ -163,8 +163,11 @@ export function buildHTTPExecutor( request: ExecutionRequest, excludeQuery?: boolean, ) => { - disposeCtrl ||= new AbortController(); - if (disposeCtrl.signal.aborted) { + // @ts-expect-error Cloudflare Workers doesn't like the shared AbortController + if (!request.cf) { + disposeCtrl ||= new AbortController(); + } + if (disposeCtrl?.signal.aborted) { return createResultForAbort(disposeCtrl.signal.reason); } const fetchFn = request.extensions?.fetch ?? options?.fetch ?? defaultFetch; @@ -214,7 +217,10 @@ export function buildHTTPExecutor( request.extensions = restExtensions; } - const signals = [disposeCtrl.signal]; + const signals = []; + if (disposeCtrl?.signal) { + signals.push(disposeCtrl.signal); + } const signalFromRequest = request.signal || request.info?.signal; if (signalFromRequest) { if (signalFromRequest.aborted) { @@ -229,7 +235,7 @@ export function buildHTTPExecutor( signals.push(subscriptionCtrl.signal); } - const signal = abortSignalAny(signals); + const signal = signals.length ? abortSignalAny(signals) : undefined; const upstreamErrorExtensions: UpstreamErrorExtensions = { request: {