withastro/astro · error · Error
Incorrect transform returned by `parseURL`
Error message
Incorrect transform returned by `parseURL`
What it means
After imageService.parseURL(url, imageConfig), the endpoint checks the returned transform object has a src. If parseURL returns null/undefined or an object without src, the optimization URL could not be parsed into a valid transform, and a plain Error is thrown.
Source
Thrown at packages/astro/src/assets/endpoint/generic.ts:26
import { etag } from '../utils/etag.js';
import { loadImage } from './loadImage.js';
/**
* Endpoint used in dev and SSR to serve optimized images by the base image services
*/
export const GET: APIRoute = async ({ request }) => {
try {
const imageService = await getConfiguredImageService();
if (!('transform' in imageService)) {
throw new Error('Configured image service is not a local service');
}
const url = new URL(request.url);
const transform = await imageService.parseURL(url, imageConfig);
if (!transform?.src) {
throw new Error('Incorrect transform returned by `parseURL`');
}
let inputBuffer: ArrayBuffer | undefined = undefined;
const isRemoteImage = isRemotePath(transform.src);
if (isRemoteImage && isRemoteAllowed(transform.src, imageConfig) === false) {
return new Response('Forbidden', { status: 403 });
}
const sourceUrl = new URL(transform.src, url.origin);
// Have we been tricked into thinking this is local?
if (!isRemoteImage && sourceUrl.origin !== url.origin) {
return new Response('Forbidden', { status: 403 });
}
inputBuffer = await loadImage(View on GitHub (pinned to d081033d5f)
Solutions
- Request optimized images through <Image>/<Picture> or getImage() so URLs are well-formed.
- If you ship a custom local service, make parseURL return { src, width, height, format, ... }.
- Do not hand-build optimization endpoint URLs.
Example fix
// before - hand-crafted request
fetch('/_image?href=');
// after - go through the component so the URL is built correctly
import { Image } from 'astro:assets';
<Image src={myImg} widths={[240, 540, 720]} sizes="..." /> Defensive patterns
Strategy: validation
Validate before calling
// Do not hand-build optimization URLs; use getImage()/Image so parseURL always returns src.
import { getImage } from 'astro:assets';
const img = await getImage({ src: mySrc, width: 540, format: 'webp' });
// img.src is a valid optimization URL. Type guard
function isValidTransform(t: any): t is { src: string } {
return t && typeof t === 'object' && typeof t.src === 'string' && t.src.length > 0;
} Try / catch
try {
await getConfiguredImageService().then((s) => s.parseURL?.(new URL(req.url), imageConfig));
} catch (e) {
if (e instanceof Error && /parseURL/i.test(e.message)) return new Response('Bad image URL', { status: 400 });
throw e;
} Prevention
- Always request optimized images via <Image>/<Picture>/getImage().
- If shipping a custom service, return { src, ... } from parseURL.
- Never construct _image URLs by hand.
When it happens
Trigger: A malformed image-optimization URL (missing the href/query parameters the service expects), or a custom local service whose parseURL does not extract/return src.
Common situations: Hand-crafting or manually editing the _image URL; a custom service with a buggy parseURL; stale URLs after changing the service.
Related errors
- Configured image service is not a local service
- Configured image service is not a local service
- Failed to parse image reference: ${imagePath}
- ImageMissingAlt
- ImageMissingAlt
AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12).
Data as JSON: /api/errors/6aca2d5b57c3e965.
Report an issue: GitHub.