withastro/astro · error · Error

Incorrect transform returned by `parseURL`

Error message

Incorrect transform returned by `parseURL`

What it means

Thrown by the dev/SSR `/_image` endpoint (packages/astro/src/assets/endpoint/generic.ts:26) when the configured service's `parseURL(url, imageConfig)` returns undefined/null or an object without a usable `src`. `parseURL` is what decodes the endpoint's query string (href, w, h, f, q) into a transform, so a URL the service cannot decode produces this error; it is caught and turned into a 500 response.

Solutions

  1. Use the URLs produced by `getImage()` / `<Image>` to reach `/_image` — they always include every param the built-in services' `parseURL` requires.
  2. If calling `/_image` manually, include the required params, e.g. `/_image?href=%2Fassets%2Fimg.png&w=800&f=webp`.
  3. Custom service authors: make `parseURL()` return an object with a non-empty `src` for every URL shape your `getUrl()` can emit, and unit-test the getUrl/parseURL round-trip.

Example fix

// before — hand-written, missing the href param
const src = '/_image?w=800&f=webp';

// after — let getImage build the URL
import { getImage } from 'astro:assets';
const src = (await getImage({ src: '/assets/img.png', width: 800, format: 'webp' })).src;
Defensive patterns

Strategy: validation

Validate before calling

// before proxying/rewriting any /_image request, keep the required params intact
const u = new URL(request.url);
if (!u.searchParams.has('href')) {
  return new Response('Missing href param', { status: 400 });
}

Prevention

When it happens

Trigger: Requesting `/_image` without the params the built-in services require (e.g. missing `?href=...`), or a custom image service whose `parseURL` implementation returns a malformed object (no `src`) for URLs its own `getUrl` generated.

Common situations: Hand-crafted or truncated `/_image` URLs; rewriting/proxying layers stripping query params; upgrading Astro versions where the endpoint's query param names changed while a custom service still parsed the old format.

Related errors


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

Appendix: 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, logger }) => {
	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, logger);

		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 e294953aa8)