{"record":{"id":"6c927c4f323f058c","repo":"ComposioHQ/composio","slug":"url-file-uploads-are-not-supported-in-edge-runtime","errorCode":null,"errorMessage":"URL file uploads are not supported in edge runtimes because the destination cannot be safely validated","messagePattern":"URL file uploads are not supported in edge runtimes because the destination cannot be safely validated","errorType":"exception","errorClass":"ComposioBlockedInternalUrlError","httpStatus":null,"severity":"error","filePath":"ts/packages/core/src/utils/ssrfGuard.workerd.ts","lineNumber":9,"sourceCode":"import { ComposioBlockedInternalUrlError } from '../errors/SsrfErrors';\n\n/**\n * Edge runtimes do not expose the DNS resolution APIs needed to prove that a\n * hostname is publicly routable before connecting. Fail closed instead of\n * falling back to an unguarded fetch.\n */\nexport const ssrfSafeFetch = async (rawUrl: string): Promise<Response> => {\n  throw new ComposioBlockedInternalUrlError(\n    'URL file uploads are not supported in edge runtimes because the destination cannot be safely validated',\n    {\n      url: rawUrl,\n      possibleFixes: [\n        'Fetch the public URL yourself and pass a File or ArrayBuffer instead',\n        'Run the URL upload in a Node.js or Bun runtime',\n      ],\n    }\n  );\n};\n\n/**\n * Unguarded `fetch`, for the call sites that must keep working here.\n *\n * Failing closed is the right default for a URL the caller chose to upload, but\n * applying it to Tool Router session file transfers would take a working\n * feature away from Workers instead of closing a hole reachable there. The\n * guard exists to stop a URL from reaching private address space the SDK's host","sourceCodeStart":1,"sourceCodeEnd":27,"githubUrl":"https://github.com/ComposioHQ/composio/blob/64b1b85502b1beeb2379e6c9e8bf1104504fa637/ts/packages/core/src/utils/ssrfGuard.workerd.ts#L1-L27","documentation":"The edge-runtime (workerd/Cloudflare Workers) build of ssrfSafeFetch intentionally fails closed: edge runtimes expose no DNS resolution API, so the SDK cannot prove a hostname is publicly routable before connecting. All URL-based file uploads are therefore unsupported there.","triggerScenarios":"Calling a URL-upload API that routes through ssrfSafeFetch inside a Cloudflare Worker / Vercel Edge / other workerd runtime — the function throws unconditionally on every call.","commonSituations":"Deploying code that worked in Node.js to an edge runtime without changing the upload strategy; edge functions that accept user-supplied file URLs.","solutions":["Fetch the URL yourself in the edge runtime and pass the File/ArrayBuffer to the upload API instead of the URL","Move the URL-upload flow to a Node.js or Bun runtime","Guard the code path by environment so edge deployments skip URL uploads"],"exampleFix":"// before (in a Cloudflare Worker)\nawait upload.uploadFileAtUrl(url);\n\n// after\nconst res = await fetch(url);\nconst file = await res.blob();\nawait upload.uploadFile(file);","handlingStrategy":"fallback","validationCode":"// detect edge runtimes and switch strategy up front\nconst isEdge = typeof navigator !== 'undefined' && navigator.userAgent?.includes('Cloudflare-Workers');\nconst input = isEdge ? await (await fetch(url)).blob() : url;","typeGuard":null,"tryCatchPattern":"try {\n  await upload.uploadFileAtUrl(url);\n} catch (e) {\n  if (e instanceof ComposioBlockedInternalUrlError && /edge runtimes/.test(e.message)) {\n    const file = await (await fetch(url)).blob();\n    return upload.uploadFile(file);\n  }\n}","preventionTips":["Never use URL-based uploads in Workers/edge runtimes; pass File/ArrayBuffer","Branch upload strategy on runtime early in design","Run URL-upload flows in Node.js or Bun services"],"tags":["ssrf","edge-runtime","cloudflare-workers","file-upload","platform-limitation"],"backgroundTag":"unsupported-runtime-api","analyzedSha":"64b1b85502b1beeb2379e6c9e8bf1104504fa637","analyzedAt":"2026-08-28T15:39:33.623Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}