withastro/astro · error · AstroError

ExpectedImage

ExpectedImage

Error message

Expected `src` property for `getImage` or `<Image />` to be either an ESM imported image or a string with the path of a remote image. Received `${src}` (type: `${typeofOptions}`).\n\nFull serialized options received: `${fullOptions}`.

What it means

Thrown by verifyOptions() in the base image service when src is falsy or is neither a remote-image string nor an ESM-imported image. The guard `!options.src || (!isRemoteImage && !isESMImportedImage)` rejects empty strings, null, numbers, or any value that is not a string and not an object with import metadata.

Source

Thrown at packages/astro/src/assets/services/service.ts:148

}

export type BaseServiceTransform = {
	src: string;
	width?: number;
	height?: number;
	format?: string;
	quality?: string | null;
	fit?: ImageFit;
	position?: string;
	background?: string;
};

const sortNumeric = (a: number, b: number) => a - b;

export function verifyOptions(options: ImageTransform): void {
	// `src` is missing or is `undefined`.
	if (!options.src || (!isRemoteImage(options.src) && !isESMImportedImage(options.src))) {
		throw new AstroError({
			...AstroErrorData.ExpectedImage,
			message: AstroErrorData.ExpectedImage.message(
				JSON.stringify(options.src),
				typeof options.src,
				JSON.stringify(options, (_, v) => (v === undefined ? null : v)),
			),
		});
	}

	if (!isESMImportedImage(options.src)) {
		// User passed an `/@fs/` path or a filesystem path instead of the full image.
		if (
			options.src.startsWith('/@fs/') ||
			(!isRemotePath(options.src) && !options.src.startsWith('/'))
		) {
			throw new AstroError({
				...AstroErrorData.LocalImageUsedWrongly,
				message: AstroErrorData.LocalImageUsedWrongly.message(options.src),

View on GitHub (pinned to d081033d5f)

Solutions

  1. Ensure src is either an ESM-imported asset or a non-empty remote URL string.
  2. Guard upstream: if (!src) return null; before rendering.
  3. Re-check that imported assets resolve (no broken paths) so src isn't ''.
  4. If passing an object, pass the Astro import metadata, not a raw buffer.

Example fix

// before
<Image src={entry.data.maybeMissingUrl} />

// after
{entry.data.maybeMissingUrl && <Image src={entry.data.maybeMissingUrl} width={800} height={600} />}
Defensive patterns

Strategy: validation

Validate before calling

import { isESMImportedImage, isRemoteImage } from 'astro/assets/utils';
function isValidSrc(src: unknown): boolean {
  return (typeof src === 'string' && src.length > 0) || isESMImportedImage(src as any);
}

Type guard

function isValidImageSrc(src: unknown): src is string | ImageMetadata {
  return (typeof src === 'string' && src.length > 0) || (typeof src === 'object' && src !== null && 'fsPath' in src);
}

Prevention

When it happens

Trigger: Calling the image service with verifyOptions(options) where options.src is '', null, 0, false, a plain object lacking import metadata, a number, or any non-string/non-ImageMetadata value. isRemoteImage is true only for strings; isESMImportedImage is true only for objects/functions with import shape.

Common situations: An empty image URL pulled from a CMS field, a broken import that resolved to undefined-coerced-to-string, passing a Buffer/File instead of an import, or a dynamic src that evaluated to a non-image value.

Related errors


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