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

  1. Request optimized images through <Image>/<Picture> or getImage() so URLs are well-formed.
  2. If you ship a custom local service, make parseURL return { src, width, height, format, ... }.
  3. 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

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


AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12). Data as JSON: /api/errors/6aca2d5b57c3e965. Report an issue: GitHub.