Skip to content

next/image fixed-width emits a non-allowed srcSet width → /_next/image 400 + failed <head> preload #8

Description

@hyf0

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions