Problem
For a fixed-width next/image (a width prop, no sizes/fill), vinext emits a single width-descriptor srcSet entry at the literal width and points src + the <head> preload at that width. The /_next/image optimizer then 400s any width not in deviceSizes/imageSizes.
Repro
for w in 48 63 64 313 384 640; do
curl -s -o /dev/null -w "w=$w -> %{http_code}\n" \
"http://localhost:3000/_next/image?url=%2Fimages%2Fuwu.png&w=$w&q=75"
done
# 63 -> 400, 64 -> 200, 313 -> 400, 384 -> 200
react.dev's logo uses <Image priority width={63} height={32}> (TopNav) and width={313} (HomeContent). Because of priority, a failed fetchPriority=high image preload is emitted in every page's <head> (...&w=63&q=75 63w), 400ing on every navigation. width={63} is valid Next usage — Next snaps the emitted width to an allowed size.
Workaround used
Change the width props to allowed sizes (63→64, 313→384).
Suggested fix
Snap the emitted srcSet/preload width to the nearest allowed imageSizes/deviceSizes (or have the optimizer round w up) instead of returning 400.
Related (separate but adjacent)
On the node origin (vinext start), /_next/image is a pass-through: it validates w/q but never resizes/transcodes and sends no Vary: Accept (documented "no local optimization yet"). The Cloudflare deploy path optimizes via env.IMAGES, so this is origin-only — noting it here for completeness.
Problem
For a fixed-width
next/image(awidthprop, nosizes/fill), vinext emits a single width-descriptor srcSet entry at the literal width and pointssrc+ the<head>preload at that width. The/_next/imageoptimizer then 400s any width not indeviceSizes/imageSizes.Repro
react.dev's logo uses
<Image priority width={63} height={32}>(TopNav) andwidth={313}(HomeContent). Because ofpriority, a failedfetchPriority=highimage preload is emitted in every page's<head>(...&w=63&q=75 63w), 400ing on every navigation.width={63}is valid Next usage — Next snaps the emitted width to an allowed size.Workaround used
Change the width props to allowed sizes (63→64, 313→384).
Suggested fix
Snap the emitted srcSet/preload width to the nearest allowed
imageSizes/deviceSizes(or have the optimizer roundwup) instead of returning 400.Related (separate but adjacent)
On the node origin (
vinext start),/_next/imageis a pass-through: it validatesw/qbut never resizes/transcodes and sends noVary: Accept(documented "no local optimization yet"). The Cloudflare deploy path optimizes viaenv.IMAGES, so this is origin-only — noting it here for completeness.