{"record":{"id":"a2326eeb3a6f286c","repo":"vercel/next.js","slug":"the-requested-resource-isn-t-a-valid-image","errorCode":null,"errorMessage":"The requested resource isn't a valid image.","messagePattern":"The requested resource isn't a valid image\\.","errorType":"http","errorClass":"ImageError","httpStatus":400,"severity":"error","filePath":"packages/next/src/server/image-optimizer.ts","lineNumber":1095,"sourceCode":"    getMaxAge(imageUpstream.cacheControl)\n  )\n\n  const upstreamType = await detectContentType(upstreamBuffer)\n\n  if (\n    !upstreamType ||\n    !upstreamType.startsWith('image/') ||\n    upstreamType.includes(',')\n  ) {\n    if (!opts.silent) {\n      Log.error(\n        \"The requested resource isn't a valid image for\",\n        href,\n        'received',\n        upstreamType\n      )\n    }\n    throw new ImageError(400, \"The requested resource isn't a valid image.\")\n  }\n  if (\n    upstreamType.startsWith('image/svg') &&\n    !nextConfig.images.dangerouslyAllowSVG\n  ) {\n    if (!opts.silent) {\n      Log.error(\n        `The requested resource \"${href}\" has type \"${upstreamType}\" but dangerouslyAllowSVG is disabled. Consider adding the \"unoptimized\" property to the <Image>.`\n      )\n    }\n    throw new ImageError(\n      400,\n      '\"url\" parameter is valid but image type is not allowed'\n    )\n  }\n  if (ANIMATABLE_TYPES.includes(upstreamType) && isAnimated(upstreamBuffer)) {\n    if (!opts.silent) {\n      Log.warnOnce(","sourceCodeStart":1077,"sourceCodeEnd":1113,"githubUrl":"https://github.com/vercel/next.js/blob/0ae8c72462952df163f1b1e0726641bc5b40dc93/packages/next/src/server/image-optimizer.ts#L1077-L1113","documentation":"Thrown by imageOptimizer after the upstream/internal image bytes are fetched: detectContentType returned null, a non-'image/' MIME, or a comma-containing type. The content at the URL is not a recognizable image, so optimization cannot proceed.","triggerScenarios":"The fetched bytes are HTML (e.g. a 404 page), JSON, a text error page, or a corrupted/truncated image whose magic bytes don't match any known image format. detectContentType sniffs the byte signature.","commonSituations":"The image URL returns an HTML error page with a 200 status (soft 404), the upstream returns a login redirect page, the file extension lies about content, or the image is truncated mid-download.","solutions":["Open the image URL directly in a browser and confirm it serves actual image bytes, not an HTML/JSON page.","Fix the source URL to point at a real image asset (check for 404/redirect/login walls).","Ensure the upstream sets a correct Content-Type and returns the full file without truncation.","If serving SVG, note this specific error path rejects SVG only when not detected as image; see dangerouslyAllowSVG for SVG handling."],"exampleFix":"// before: URL returns an HTML 404 page with 200 status\n<Image src=\"https://example.com/missing.png\" />\n\n// after: point to a real image asset\n<Image src=\"https://example.com/real-photo.png\" />","handlingStrategy":"type-guard","validationCode":"const res = await fetch(url)\nconst type = res.headers.get('content-type') || ''\nif (!type.startsWith('image/')) throw new Error(`${url} is not an image (got ${type})`)","typeGuard":"import { fileTypeFromBuffer } from 'file-type'\nasync function isImage(buf: Buffer): Promise<boolean> {\n  const t = await fileTypeFromBuffer(buf)\n  return !!t && t.mime.startsWith('image/')\n}","tryCatchPattern":"try {\n  return <Image src={url} ... />\n} catch (e) {\n  if (e.message.includes(\"isn't a valid image\")) return <FallbackImg />\n  throw e\n}","preventionTips":["Verify image URLs resolve to actual image bytes before using next/image.","Watch for soft-404 HTML pages returned with 200 status.","Validate Content-Type headers from upstream sources."],"tags":["image-optimizer","invalid-content","content-type"],"analyzedSha":"0ae8c72462952df163f1b1e0726641bc5b40dc93","analyzedAt":"2026-08-06T19:44:29.143Z","schemaVersion":2},"datasetVersion":"2026-08-07T02:17:10.218Z"}