payloadcms/payload · error · APIError

The provided file URL is not allowed.

Error message

The provided file URL is not allowed.

What it means

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.

Source

Thrown at packages/plugin-mcp/src/mcp/builtin/collections/fileInput.ts:106

  } else {
    if (uploadConfig.pasteURL === false) {
      throw new APIError(
        `Uploading files from URLs is disabled for collection "${collectionSlug}".`,
        400,
      )
    }

    const url = new URL(input.url)

    if (!['http:', 'https:'].includes(url.protocol)) {
      throw new APIError('File URLs must use http or https.', 400)
    }

    if (
      typeof uploadConfig.pasteURL === 'object' &&
      !isURLAllowed(input.url, uploadConfig.pasteURL.allowList)
    ) {
      throw new APIError('The provided file URL is not allowed.', 400)
    }

    file = await getExternalFile({
      data: {
        filename: sanitizeFilename(input.name || getURLFilename(url)),
        url: input.url,
      } as FileData,
      req,
      uploadConfig: {
        ...uploadConfig,
        externalFileHeaderFilter: uploadConfig.externalFileHeaderFilter ?? (() => ({})),
      },
    })
    file.mimetype = file.mimetype?.split(';')[0] || 'application/octet-stream'
    file.size = file.data.length
  }

  if (maxFileSize !== undefined && Number.isFinite(maxFileSize) && file.size > maxFileSize) {

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Add the URL's host to `upload.pasteURL.allowList` (using the same hostname format `isURLAllowed` expects)
  2. Re-fetch the file yourself from an allowed host and pass it as `source: 'base64'`
  3. Double-check the exact hostname, port, and trailing-slash against what `isURLAllowed` matches

Example fix

// before
upload: { staticURL: '/media', pasteURL: { allowList: ['cdn.example.com'] } }
// url supplied: https://assets.example.com/x.png
// after — add the missing host
upload: { staticURL: '/media', pasteURL: { allowList: ['cdn.example.com', 'assets.example.com'] } }
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check the URL host against the collection's allowList
import { isURLAllowed } from 'payload/internal'
const allowed = isURLAllowed(url, uploadCfg.pasteURL && typeof uploadCfg.pasteURL === 'object' ? uploadCfg.pasteURL.allowList : undefined)
if (!allowed) throw new Error(`${url} not in pasteURL allowList`)

Try / catch

import { APIError } from 'payload'
try {
  await tool.call({ source: 'externalURL', url })
} catch (e) {
  if (e instanceof APIError && e.statusCode === 400 && /not allowed/.test(e.message)) {
    // surface to user: ask an admin to add the host, or pick a different source
  }
  throw e
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12). Data as JSON: /api/errors/1936cdbc3dbbd216. Report an issue: GitHub.