{"record":{"id":"fea249d0935acb36","repo":"payloadcms/payload","slug":"invalid-file-url","errorCode":null,"errorMessage":"Invalid file url","messagePattern":"Invalid file url","errorType":"http","errorClass":"APIError","httpStatus":400,"severity":"error","filePath":"packages/payload/src/uploads/getExternalFile.ts","lineNumber":108,"sourceCode":"\n      break\n    }\n\n    if (!res || !res.ok) {\n      throw new APIError(`Failed to fetch file from ${fileURL}`, res?.status)\n    }\n\n    const data = await res.arrayBuffer()\n\n    return {\n      name: filename,\n      data: Buffer.from(data),\n      mimetype: res.headers.get('content-type') || undefined!,\n      size: Number(res.headers.get('content-length')) || 0,\n    }\n  }\n\n  throw new APIError('Invalid file url', 400)\n}\n","sourceCodeStart":90,"sourceCodeEnd":110,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/payload/src/uploads/getExternalFile.ts#L90-L110","documentation":"`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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Ensure `url` is stored as a string (or omitted) on upload documents; never an object/null when remote fetching is expected.","Run a data audit: find documents where `typeof url !== 'string'` and repair or delete them.","For local-storage collections, either keep `disableLocalStorage: false` so files live locally, or supply a valid absolute URL string.","Review custom `beforeChange`/`afterRead` hooks that transform `url`."],"exampleFix":"// before — url stored as null on a remote-upload doc\n{ filename: 'a.png', url: null }\n\n// after — store a valid string url\nawait payload.update({ collection: 'media', id, data: { url: 'https://cdn.example.com/a.png' } })","handlingStrategy":"type-guard","validationCode":"function isStringUrl(url: unknown): url is string {\n  return typeof url === 'string' && url.length > 0\n}\n\nif (!isStringUrl(doc.url)) {\n  // repair: set a valid URL string or remove the field\n  throw new Error('doc.url must be a string')\n}","typeGuard":"const isStringUrl = (url: unknown): url is string => typeof url === 'string' && url.length > 0","tryCatchPattern":"try {\n  await payload.update({ collection: 'media', id, data })\n} catch (err) {\n  if (err instanceof Error && /invalid file url/i.test(err.message)) {\n    // audit and repair non-string url fields on upload documents\n  } else throw err\n}","preventionTips":["Never store non-string values in the `url` field of upload documents.","Audit migrations that may have written null/object urls.","Validate `url` type in `beforeChange` hooks."],"tags":["upload","type-validation","external-file","data-integrity"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}