# Troubleshooting

URL: /docs/plugins/payload-images/troubleshooting

Fix the common payload-images failures fast — 404s, missing admin panels, over-fetching, off-center crops, and stale pages.

Each failure below leads with what you see, then the cause, then the fix. Scan the first column for
your symptom.

| Symptom                                                                                                                                         | Cause                                                                                                                                                                                                                                                                              | Fix                                                                                                                                                                                                                                                                                                                                                                                     |
| ----------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| An `<img>` `src` points at `/api/img/…` but returns **404**, or images never optimize.                                                          | Sharp is being bundled — its native binary breaks when bundled.                                                                                                                                                                                                                    | Add `serverExternalPackages: ['sharp']` to `next.config.ts` (Turbopack and webpack both need it).                                                                                                                                                                                                                                                                                       |
| `src`/`srcset` are absent from a read.                                                                                                          | An explicit `select` left them out — the virtual URL fields are always registered, but a `select` still decides what comes back.                                                                                                                                                   | Add them to the `select`, or use the ready-made `RESPONSIVE_IMAGE_SELECT`. See [Rendering images](/docs/plugins/payload-images/rendering).                                                                                                                                                                                                                                              |
| The focal-point picker or the **Presets & variants** panel is missing or blank in the admin.                                                    | Admin components register by string path; the import map is stale.                                                                                                                                                                                                                 | Run `pnpm payload generate:importmap` and restart the dev server. (`collections.images.options.focalUI` defaults on, so the components are registered.)                                                                                                                                                                                                                                 |
| The browser downloads a huge image into a small slot (over-fetching).                                                                           | `sizes` left at its `100vw` default.                                                                                                                                                                                                                                               | Set `sizes` to how big the image actually renders, e.g. `sizes="(max-width: 768px) 100vw, 33vw"`. See [Rendering images](/docs/plugins/payload-images/rendering).                                                                                                                                                                                                                       |
| The crop is off-center or the wrong shape.                                                                                                      | The CSS box disagrees with the crop — usually an `aspectRatio` passed to the component that differs from the one the read declared.                                                                                                                                                | Declare it **once, on the read** (`imageFor(id).aspectRatio('16:9')`) and let the doc spread carry it. Only pass `aspectRatio` to the component when you deliberately want a different box; for the focal point itself, see [Focal point & crop](/docs/plugins/payload-images/metadata#focal-point-hotspot--crop).                                                                      |
| Edited an image but a page still shows the old one.                                                                                             | The page is cached. Image URLs self-bust; the page cache doesn't.                                                                                                                                                                                                                  | Revalidate that route. See [Caching → Revalidation](/docs/plugins/payload-images/caching#revalidation).                                                                                                                                                                                                                                                                                 |
| A bulk upload reports errors, and re-uploading one of those files now fails at the storage provider — that filename is unusable no matter what. | `clientUploads` puts the file in the store *before* the document is validated, and the admin's bulk-upload screen submits without validating first. A rejected save (a missing `alt`, most often) leaves an object no document owns, and the provider won't write that name twice. | Turn on the adapter's random-suffix option for the client-upload collections — e.g. `vercelBlobStorage({ clientUploads: true, addRandomSuffix: true, … })`. Every attempt then writes a new name, so a rejected save costs a stray object instead of the filename. Leave it off for server-side collections, which upload after validation and keep clean names. See the callout below. |
| Boot fails with `[payload-images] collections.images: field(s) … are already defined by the plugin`.                                            | A field in your `collections.images.overrides.fields` has the same name as one the plugin injects (`alt`, `variants`, `placeholder`, `palette`, …) — overrides append, so the name would collide.                                                                                  | Rename or remove your field. See [Collections → Renaming a collection](/docs/plugins/payload-images/collections#renaming-a-collection-and-adding-your-own-fields).                                                                                                                                                                                                                      |
| The prewarm plan shows fewer variants than expected, or the status endpoint / admin panel reports the plan is capped.                           | The strategy derives more targets than `maxVariantsPerImage` (default 32) allows — the plan is `truncated`: lower-priority units (quieter learned profiles first) lose budget first, and a unit that doesn't fit keeps an even spread of its widths.                               | Raise `options.prewarm.maxVariantsPerImage`, or narrow the strategy (`widths: { every: 2 }`, fewer `seeds`, `learned: false`). See [Prewarming → What gets warmed](/docs/plugins/payload-images/prewarming#what-gets-warmed).                                                                                                                                                           |
| Uploads succeed but prewarm jobs pile up and never run.                                                                                         | `strategy.autoRun: false` turns off all three built-in runners (the cron, the post-upload kick, the image-traffic drain) — or the queue only holds a big CLI-enqueued backlog on a site with too little traffic to drain it.                                                       | Leave `autoRun` on (the kick and drain cover serverless too), or run the jobs yourself: a cron hitting `/api/payload-jobs/run?queue=images-prewarm` (e.g. a Vercel Cron), or `payload images:prewarm --now` as a build step. See [Prewarming → When it runs](/docs/plugins/payload-images/prewarming#when-it-runs).                                                                     |

> **With `clientUploads`, storage is written before the document is validated.** The browser sends
> the file straight to the provider and only then posts the document, so nothing server-side — no
> hook of this plugin's or Payload's — runs early enough to stop a rejected save from orphaning the
> object. A random suffix is what keeps that orphan from costing you the filename; server-side
> uploads don't need it, because they're written from an `afterChange` hook once the document is
> already saved.
>
> Don't gate `clientUploads` on `NODE_ENV`. Running server uploads in dev and client uploads in
> production means the two paths differ in exactly the way that matters, and a failure like this one
> can't reproduce locally. Turn it on in both, and let dev exercise what production does.

> **Image URLs self-bust; your page cache doesn't.** A cached page keeps serving the old URL until
> you revalidate that route — exactly as it would for any Payload content. Content-addressed URLs
> refresh themselves on file replace or focal move; the page serving them does not.
