payloadcms/payload · error · APIError

Invalid file url

Error message

Invalid file url

What it means

`getExternalFile` only enters the fetch branch when `typeof url === 'string'`. If the `data.url` on the document is not a string (null, undefined, number, object), the function falls through to the final `throw new APIError('Invalid file url', 400)`. This is a defensive type check: a non-string URL cannot be fetched.

Source

Thrown at packages/payload/src/uploads/getExternalFile.ts:108

      break
    }

    if (!res || !res.ok) {
      throw new APIError(`Failed to fetch file from ${fileURL}`, res?.status)
    }

    const data = await res.arrayBuffer()

    return {
      name: filename,
      data: Buffer.from(data),
      mimetype: res.headers.get('content-type') || undefined!,
      size: Number(res.headers.get('content-length')) || 0,
    }
  }

  throw new APIError('Invalid file url', 400)
}

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Ensure `url` is stored as a string (or omitted) on upload documents; never an object/null when remote fetching is expected.
  2. Run a data audit: find documents where `typeof url !== 'string'` and repair or delete them.
  3. For local-storage collections, either keep `disableLocalStorage: false` so files live locally, or supply a valid absolute URL string.
  4. Review custom `beforeChange`/`afterRead` hooks that transform `url`.

Example fix

// before — url stored as null on a remote-upload doc
{ filename: 'a.png', url: null }

// after — store a valid string url
await payload.update({ collection: 'media', id, data: { url: 'https://cdn.example.com/a.png' } })
Defensive patterns

Strategy: type-guard

Validate before calling

function isStringUrl(url: unknown): url is string {
  return typeof url === 'string' && url.length > 0
}

if (!isStringUrl(doc.url)) {
  // repair: set a valid URL string or remove the field
  throw new Error('doc.url must be a string')
}

Type guard

const isStringUrl = (url: unknown): url is string => typeof url === 'string' && url.length > 0

Try / catch

try {
  await payload.update({ collection: 'media', id, data })
} catch (err) {
  if (err instanceof Error && /invalid file url/i.test(err.message)) {
    // audit and repair non-string url fields on upload documents
  } else throw err
}

Prevention

When it happens

Trigger: A duplication/re-upload where `incomingFileData.url` is not a string — null, undefined, a number, an array, or an object — while the code path expects to fetch it remotely (filename present but not treated as a local file).

Common situations: A document was created with `disableLocalStorage` and an object/null `url`. A migration wrote a non-string `url`. A custom hook mutated `url` to an object. The `url` field was unset but `filename` remains, and the document is neither local nor fetchable.

Related errors


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