withastro/astro · error · AstroError
ExpectedNotESMImage
ExpectedNotESMImage
Error message
An ESM-imported image cannot be passed directly to `getImage()`. Instead, pass an object with the image in the `src` property.
What it means
Thrown by getImage() when the entire options object is itself an ESM-imported image metadata object rather than a transform containing src. isImageMetadata(options) detects the non-enumerable fsPath marker that Astro injects on imports, meaning the user passed the imported image directly instead of wrapping it in { src }.
Source
Thrown at packages/astro/src/assets/internal.ts:70
if (!options || typeof options !== 'object') {
throw new AstroError({
...AstroErrorData.ExpectedImageOptions,
message: AstroErrorData.ExpectedImageOptions.message(JSON.stringify(options)),
});
}
if (typeof options.src === 'undefined') {
throw new AstroError({
...AstroErrorData.ExpectedImage,
message: AstroErrorData.ExpectedImage.message(
options.src,
'undefined',
JSON.stringify(options),
),
});
}
if (isImageMetadata(options)) {
throw new AstroError(AstroErrorData.ExpectedNotESMImage);
}
const service = await getConfiguredImageService();
// If the user inlined an import, something fairly common especially in MDX, or passed a function that returns an Image, await it for them
const resolvedOptions: ImageTransform = {
...options,
src: await resolveSrc(options.src),
};
let originalWidth: number | undefined;
let originalHeight: number | undefined;
// Infer size for remote images if inferSize is true
if (resolvedOptions.inferSize) {
delete resolvedOptions.inferSize; // Delete so it doesn't end up in the attributes
if (isRemoteImage(resolvedOptions.src) && isRemotePath(resolvedOptions.src)) {View on GitHub (pinned to d081033d5f)
Solutions
- Wrap the imported image in a src property: getImage({ src: importedImage }).
- If using <Image />, use <Image src={importedImage} />, not <Image {...importedImage} />.
- Audit MDX components that spread imported images into getImage.
- Add a lint/type check that the first getImage argument is a transform, not an ImageMetadata.
Example fix
// before
import photo from './photo.jpg';
const img = getImage(photo);
// after
import photo from './photo.jpg';
const img = getImage({ src: photo, width: 800, height: 600 }); Defensive patterns
Strategy: type-guard
Validate before calling
import { isImageMetadata } from 'astro/assets';
function isBareImageMetadata(v: unknown): boolean {
return isImageMetadata(v);
} Type guard
import type { ImageMetadata } from 'astro';
function isImageMetadataValue(v: unknown): v is ImageMetadata {
return typeof v === 'object' && v !== null && 'fsPath' in v;
} Prevention
- Always wrap imported images: { src: imported }.
- Review MDX components that spread imported images.
- Add a type annotation that the first getImage argument is a transform.
When it happens
Trigger: Calling getImage(importedImage) instead of getImage({ src: importedImage }). The imported asset module's metadata object (with the hidden fsPath) is passed where a transform object is expected.
Common situations: Common in MDX/JSX when an author writes getImage(myImage) rather than getImage({ src: myImage }), or passes the result of an `import myImage from '...'` directly as the first argument.
Related errors
AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12).
Data as JSON: /api/errors/23825330b0dd4d29.
Report an issue: GitHub.