{"record":{"id":"d85d58a1eedeb9e5","repo":"payloadcms/payload","slug":"failed-to-fetch-the-file-from-the-provided-url","errorCode":null,"errorMessage":"Failed to fetch the file from the provided URL.","messagePattern":"Failed to fetch the file from the provided URL\\.","errorType":"http","errorClass":"APIError","httpStatus":null,"severity":"error","filePath":"packages/payload/src/uploads/endpoints/getFileFromURL.ts","lineNumber":109,"sourceCode":"      redirectCount++\n      if (redirectCount > maxRedirects) {\n        throw new APIError('Too many redirects.', 403)\n      }\n      const location = response.headers.get('location')\n      if (location) {\n        fileURL = new URL(location, fileURL).href\n        if (hasAllowList && !isURLAllowed(fileURL, config.upload.pasteURL.allowList)) {\n          throw new APIError('The provided URL is not allowed.', 400)\n        }\n        continue\n      }\n    }\n\n    break\n  }\n\n  if (!response.ok) {\n    throw new APIError('Failed to fetch the file from the provided URL.', response.status)\n  }\n\n  const rawFileName = decodeURIComponent(new URL(fileURL).pathname.split('/').pop() || '')\n  const safeFileName = sanitizeFilename(rawFileName)\n  const encodedFileName = encodeURIComponent(safeFileName).replace(\n    /['()]/g,\n    (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`,\n  )\n  // Strip quotes, backslashes, and control chars from the ASCII fallback\n  const asciiFileName = safeFileName.replace(/[\"\\\\\\r\\n]/g, '_')\n\n  const headers: Record<string, string> = {\n    'Content-Disposition': `attachment; filename=\"${asciiFileName}\"; filename*=UTF-8''${encodedFileName}`,\n    'Content-Type': response.headers.get('content-type') || 'application/octet-stream',\n  }\n\n  const contentLength = response.headers.get('content-length')\n  if (contentLength) {","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/payload/src/uploads/endpoints/getFileFromURL.ts#L91-L127","documentation":"APIError thrown with the remote response's status code when response.ok is false after the redirect loop completes (non-2xx, non-3xx final response). The handler does not retry; it surfaces the upstream HTTP failure with the remote's status as the APIError status.","triggerScenarios":"The remote src URL resolves to a final response with status >= 400 (or any non-2xx outside the redirect range), e.g. 404 Not Found, 403 Forbidden, 500 from the origin, or a 4xx from an expired signed URL. Also fires on 5xx server errors upstream.","commonSituations":"Linked file was deleted at the origin (404); the URL requires auth/cookies the server doesn't have (401/403); expired S3 signed URL; origin temporarily down (5xx); geo-blocked or rate-limited origin; wrong URL pasted by the user.","solutions":["Verify the URL is reachable in a browser or via curl from the server's network.","If the URL is time-limited (signed), refresh it before calling the endpoint.","For 403/401, ensure the origin doesn't require headers/cookies the server can't provide — host the file elsewhere.","Handle the APIError status in the client and prompt the user to re-check the URL."],"exampleFix":"// client — surface the upstream status\ntry {\n  await fetch(`/api/media/paste-url?src=${encodeURIComponent(src)}`, { method: 'POST', headers }).then((r) => {\n    if (!r.ok) throw new Error(`Remote returned ${r.status}`)\n  })\n} catch (e) {\n  alert(`Could not fetch that URL (${e.message}). Check the link and try again.`)\n}","handlingStrategy":"try-catch","validationCode":"async function remoteOk(u: string): Promise<boolean> {\n  try { const r = await fetch(u, { method: 'HEAD' }); return r.ok } catch { return false }\n}\nif (!(await remoteOk(src))) throw new Error('Source URL is not reachable')","typeGuard":"const isOkStatus = (s: number): boolean => s >= 200 && s < 300","tryCatchPattern":"try {\n  await fetch(`/api/media/paste-url?src=${encodeURIComponent(src)}`, { method: 'POST' })\n} catch (e) {\n  if (/Failed to fetch the file/.test(e.message)) alert('Remote file unavailable; check the URL')\n}","preventionTips":["HEAD/GET-check the URL from the server's network before submitting.","Refresh expiring signed URLs before paste-URL calls.","Avoid paste-URL for hosts requiring cookies/auth the server lacks.","Surface the upstream status code to the user for actionable errors."],"tags":["upload","paste-url","network","upstream"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}