Debug an image optimization API

Debug image delivery as a five-stage system: browser selection, generated URL, source resolution, transformation, and edge cache. Inspect one stage at a time and keep the exact failing URL.

Short answer

First capture the browser’s currentSrc, rendered dimensions, natural dimensions, response headers, and status. Request that exact URL with a command-line client. Then compare a cache-busted request only as a diagnostic, inspect the source separately, and reduce the transform to a known preset.

Collect the minimum useful evidence

const img = document.querySelector("img[data-debug]")
console.table({
  currentSrc: img.currentSrc,
  renderedWidth: img.getBoundingClientRect().width,
  renderedHeight: img.getBoundingClientRect().height,
  naturalWidth: img.naturalWidth,
  naturalHeight: img.naturalHeight,
  complete: img.complete
})

Then inspect the network response for content type, content length, cache status, age, validator headers, and redirects. MDN lists the relevant image element properties in HTMLImageElement.

Why is the delivered file too large?

  1. Compare rendered width with natural width. If natural width is much larger, candidate selection or the requested transform is wrong.
  2. Check sizes. A declaration of 100vw for a 520-pixel content slot can make the browser choose an oversized candidate.
  3. Confirm the response content type. A URL ending in .jpg may still deliver AVIF or WebP when automatic format negotiation is working.
  4. Verify that width, crop, automatic format, and quality made it into the normalized URL in the intended order.
  5. Test the same asset class with a fixed format and quality to separate selection from encoding behavior.

Cloudinary documents automatic format, quality, and sizing in its image optimization guide. ImageKit documents its optimization behavior in image optimization. Apply each provider’s syntax exactly.

Why is the wrong format returned?

Send requests with explicit Accept headers and compare the response. If automatic negotiation is enabled, verify that the CDN varies or keys the response correctly. Check whether an intermediate proxy removed the Accept header or cached a previous response without the required variation.

curl -I -H "Accept: image/avif,image/webp,image/*" "https://media.example.com/..."
curl -I -H "Accept: image/webp,image/*" "https://media.example.com/..."
curl -I -H "Accept: image/jpeg,image/*" "https://media.example.com/..."

Do not infer from the extension alone. Inspect Content-Type. Providers may preserve a familiar path extension while negotiating a different response format.

Why is a transformed image stale?

Determine whether the source URL is immutable. If the source changed in place while the transformed URL stayed identical, every cache layer may be behaving correctly while serving old bytes. Prefer versioned source identities or change the delivery URL when the source changes.

  • Compare the source validator or version with the derivative response.
  • Request the plain canonical URL and record cache headers.
  • Use a query string only to test whether a cache bypass changes the response.
  • Purge the correct cache key. Some systems group derivatives under the source identity.
  • Retest the original canonical URL after purge; a bypassed URL is not proof visitors receive the fix.

Cloudflare explains derivative caching and purge behavior in its Images troubleshooting guide. The exact purge target differs between systems.

Why does the API return 400 or 404?

A 400 usually points to malformed parameters, a rejected signature, disallowed dimensions, or an unsupported operation. A 404 may mean the source ID does not exist, a remote origin cannot be fetched, or the delivery type is wrong.

  1. Request the untransformed source through the provider.
  2. Apply one known resize preset.
  3. Add crop, format, and quality one operation at a time.
  4. Regenerate the signature from the exact normalized parameters.
  5. Check whether URL encoding changed slashes, commas, spaces, or overlay text.

Why do signatures fail?

Signatures fail when the server signs a different normalized string from the one the edge validates. Common causes are parameter order, omitted defaults, encoding differences, a changed path, an expired timestamp, or a signing secret from the wrong environment.

Log the unsigned canonical string on the trusted server, never the secret. Recompute with the provider SDK and compare the final path byte for byte. Do not attempt to make the browser sign arbitrary transforms with a server secret.

Why are cache misses high?

  • Count distinct normalized URLs per asset and preset.
  • Look for unrounded widths, cache-busting query parameters, or parameter order changes.
  • Confirm that equivalent transformations generate one canonical URL.
  • Inspect whether authenticated cookies or headers bypass the intended public cache.
  • Check whether source redirects or errors are being cached differently from successful variants.

High cardinality is often an application bug, not a CDN problem. A component that sends its measured width as a free-form integer can create hundreds of near-identical variants.

Why does the page shift or load the hero late?

Layout shift usually means the browser did not know the image aspect ratio before bytes arrived. Add width and height or a CSS aspect ratio. A late LCP image often comes from lazy loading, CSS backgrounds, client-side discovery, an incorrect preload, or low fetch priority.

Check the responsive image guide for the markup contract. Confirm that the hero is in initial HTML, is not marked lazy, and uses high priority only when it is the actual LCP candidate.

A repeatable incident record

page URL:
viewport and DPR:
element selector:
currentSrc:
rendered / natural dimensions:
status and redirects:
content-type / content-length:
cache-status / age / etag:
source version:
expected preset:
first bad release:
canonical URL after fix:

This record separates browser behavior from provider behavior and makes the issue reproducible for another engineer.

Prevent the next incident

Turn the fix into a rule in the integration checklist, and keep candidate generation aligned with the responsive image contract.

Share with