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}`).
Full serialized options received: `${fullOptions}`. What it means
`verifyOptions()` runs inside the base image service for every `<Image>`/`<Picture>`/`getImage()` transform (packages/astro/src/assets/services/service.ts:148). The first check rejects a `src` that is falsy or neither an ESM-imported image (ImageMetadata) nor a remote URL string, throwing `ExpectedImage` with `typeof src` and the full serialized options in the message.
Solutions
- Pass either an ESM-imported image object or a full remote URL string (starting with a protocol) as `src`.
- Guard dynamic data before render: `if (typeof src !== 'string' && !isESMImport) return null`.
- Type your components' props (`src: ImageMetadata | string`) so mismatches surface at compile time.
Example fix
// before — CMS id, not a URL
<Image src={product.imageAssetId} alt={product.name} />
// after — resolve to the actual URL first
<Image src={`https://cdn.example.com/assets/${product.imageAssetId}`} alt={product.name} width={800} height={600} /> Defensive patterns
Strategy: type-guard
Validate before calling
const validSrc =
(typeof src === 'string' && /^https?:\/\//.test(src)) || isImageMetadata(src);
if (!validSrc) throw new Error(`Invalid src for <Image>: ${JSON.stringify(src)}`); Type guard
import type { ImageMetadata } from 'astro';
function isUsableImageSrc(value: unknown): value is string | ImageMetadata {
if (typeof value === 'string') return value.length > 0;
return (
typeof value === 'object' && value !== null &&
'src' in value && 'width' in value && 'height' in value
);
} Prevention
- Type the boundary where CMS data enters components and validate image fields there.
- Reject records without a usable image early instead of letting components receive junk.
When it happens
Trigger: `src` is a number, boolean, plain object, empty string, or null — e.g. `src={123}`, `src={ someObj.src }` where the property does not exist, or a CMS field rendered without a fallback.
Common situations: Untyped CMS payloads where the image field is occasionally absent/typed differently; passing `src={image.id}` instead of `src={image.url}`; templating that yields `src="[object Object]"`-like values.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- LocalImageUsedWrongly
- MissingImageDimension
- UnsupportedImageConversion
- ⚠️ Astro could not optimize image
- ⚠️ Astro expected an SVG for
AI-assisted analysis of withastro/astro@e294953aa8 (2026-08-18).
Data as JSON: /api/errors/97cdd57de43ebe6b.
Report an issue: GitHub.
Appendix: source
Thrown at packages/astro/src/assets/services/service.ts:159
}
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 e294953aa8)