withastro/astro · error · AstroError
ImageMissingAlt
ImageMissingAlt
Error message
Image missing "alt" property. "alt" text is required to describe important images on the page.
What it means
AstroError with code `ImageMissingAlt` (same code as the `<Image>` component), thrown by the `<Picture>` component at the same point in its render: after destructuring props it checks `props.alt` and throws if it is `undefined` or `null`. `<Picture>` generates multiple `<source>`s plus a fallback `<img>`, all of which inherit the same accessibility requirement, so the `alt` guard is identical.
Source
Thrown at packages/astro/components/Picture.astro:38
formats?: ImageOutputFormat[];
fallbackFormat?: ImageOutputFormat;
pictureAttributes?: HTMLAttributes<'picture'>;
};
const defaultFormats = ['webp'] as const;
const defaultFallbackFormat = 'png' as const;
// Certain formats don't want PNG fallbacks:
// - GIF will typically want to stay as a gif, either for animation or for the lower amount of colors
// - SVGs can't be converted to raster formats in most cases
// - JPEGs compress photographs and high-noise images better than PNG in most cases
// For those, we'll use the original format as the fallback instead.
const specialFormatsFallback = ['gif', 'svg', 'jpg', 'jpeg'] as const;
const { formats = defaultFormats, pictureAttributes = {}, fallbackFormat, ...props } = Astro.props;
if (props.alt === undefined || props.alt === null) {
throw new AstroError(AstroErrorData.ImageMissingAlt);
}
// Picture attribute inherit scoped styles from class and attributes
const scopedStyleClass = props.class?.match(/\bastro-\w{8}\b/)?.[0];
if (scopedStyleClass) {
if (pictureAttributes.class) {
pictureAttributes.class = `${pictureAttributes.class} ${scopedStyleClass}`;
} else {
pictureAttributes.class = scopedStyleClass;
}
}
const layout = props.layout ?? imageConfig.layout ?? 'none';
const useResponsive = layout !== 'none';
if (useResponsive) {
props.layout ??= imageConfig.layout;
props.fit ??= imageConfig.objectFit ?? 'cover';View on GitHub (pinned to d081033d5f)
Solutions
- Add a descriptive `alt` prop to `<Picture>`.
- Use `alt=""` for purely decorative pictures.
- Guard dynamic values: `alt={data.alt ?? ''}`.
- Run `astro check` to surface missing props before render.
Example fix
// before
<Picture src={hero} formats={['avif','webp']} />
// after
<Picture src={hero} formats={['avif','webp']} alt="Hero illustration of the product" /> Defensive patterns
Strategy: type-guard
Validate before calling
function hasAlt(props: unknown): props is { alt: string } {
return props != null && typeof (props as { alt?: unknown }).alt === 'string';
}
// before rendering
if (!hasAlt(props)) props.alt = data.alt ?? ''; Type guard
function hasAltProp(props: unknown): props is { alt: string } {
return props != null && typeof (props as { alt?: unknown }).alt === 'string';
} Prevention
- When migrating `<Image>` to `<Picture>`, copy the `alt` prop across.
- Default dynamic alt to '' for decorative pictures.
- Run `astro check` in CI to enforce required props.
- Enforce `alt` presence in your CMS/content schema.
When it happens
Trigger: Calling `<Picture src={...} />` (or `<Picture formats={[...]} />`) without an `alt` prop; destructuring that drops `alt`; passing `alt={null}`.
Common situations: A developer swaps `<Image>` for `<Picture>` to serve modern formats and forgets to carry over `alt`; CMS data where alt text is optional; template/partial that omits the prop.
Related errors
- ImageMissingAlt
- Configured image service is not a local service
- Incorrect transform returned by `parseURL`
- Configured image service is not a local service
- Failed to parse image reference: ${imagePath}
AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12).
Data as JSON: /api/errors/de8dada9e6ad4427.
Report an issue: GitHub.