{"record":{"id":"1936cdbc3dbbd216","repo":"payloadcms/payload","slug":"the-provided-file-url-is-not-allowed","errorCode":null,"errorMessage":"The provided file URL is not allowed.","messagePattern":"The provided file URL is not allowed\\.","errorType":"validation","errorClass":"APIError","httpStatus":400,"severity":"error","filePath":"packages/plugin-mcp/src/mcp/builtin/collections/fileInput.ts","lineNumber":106,"sourceCode":"  } else {\n    if (uploadConfig.pasteURL === false) {\n      throw new APIError(\n        `Uploading files from URLs is disabled for collection \"${collectionSlug}\".`,\n        400,\n      )\n    }\n\n    const url = new URL(input.url)\n\n    if (!['http:', 'https:'].includes(url.protocol)) {\n      throw new APIError('File URLs must use http or https.', 400)\n    }\n\n    if (\n      typeof uploadConfig.pasteURL === 'object' &&\n      !isURLAllowed(input.url, uploadConfig.pasteURL.allowList)\n    ) {\n      throw new APIError('The provided file URL is not allowed.', 400)\n    }\n\n    file = await getExternalFile({\n      data: {\n        filename: sanitizeFilename(input.name || getURLFilename(url)),\n        url: input.url,\n      } as FileData,\n      req,\n      uploadConfig: {\n        ...uploadConfig,\n        externalFileHeaderFilter: uploadConfig.externalFileHeaderFilter ?? (() => ({})),\n      },\n    })\n    file.mimetype = file.mimetype?.split(';')[0] || 'application/octet-stream'\n    file.size = file.data.length\n  }\n\n  if (maxFileSize !== undefined && Number.isFinite(maxFileSize) && file.size > maxFileSize) {","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/plugin-mcp/src/mcp/builtin/collections/fileInput.ts#L88-L124","documentation":"Thrown as a 400 when `upload.pasteURL` is configured as an object `{ allowList }` and `isURLAllowed(input.url, allowList)` returns false — the URL's host/origin is not on the operator's approved list.","triggerScenarios":"MCP tool call with `source: 'externalURL'` whose URL host is not in `upload.pasteURL.allowList`; the allowlist uses a hostname pattern that does not match (e.g. missing `www.` or wrong port).","commonSituations":"Adding a new CDN/source domain without updating the allowlist; allowlist configured with exact-host entries when subdomain or wildcard matching was expected; allowlist entries with trailing slashes or ports that differ from the supplied URL.","solutions":["Add the URL's host to `upload.pasteURL.allowList` (using the same hostname format `isURLAllowed` expects)","Re-fetch the file yourself from an allowed host and pass it as `source: 'base64'`","Double-check the exact hostname, port, and trailing-slash against what `isURLAllowed` matches"],"exampleFix":"// before\nupload: { staticURL: '/media', pasteURL: { allowList: ['cdn.example.com'] } }\n// url supplied: https://assets.example.com/x.png\n// after — add the missing host\nupload: { staticURL: '/media', pasteURL: { allowList: ['cdn.example.com', 'assets.example.com'] } }","handlingStrategy":"validation","validationCode":"// Pre-check the URL host against the collection's allowList\nimport { isURLAllowed } from 'payload/internal'\nconst allowed = isURLAllowed(url, uploadCfg.pasteURL && typeof uploadCfg.pasteURL === 'object' ? uploadCfg.pasteURL.allowList : undefined)\nif (!allowed) throw new Error(`${url} not in pasteURL allowList`)","typeGuard":null,"tryCatchPattern":"import { APIError } from 'payload'\ntry {\n  await tool.call({ source: 'externalURL', url })\n} catch (e) {\n  if (e instanceof APIError && e.statusCode === 400 && /not allowed/.test(e.message)) {\n    // surface to user: ask an admin to add the host, or pick a different source\n  }\n  throw e\n}","preventionTips":["Keep the `pasteURL.allowList` in sync with the CDN domains your app actually uses","Match exact hostnames (including subdomain and port) the way `isURLAllowed` compares them","When adding a new external source domain, update the allowlist in the same change"],"tags":["mcp","file-upload","paste-url","allowlist","security"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}