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
The built-in `<Picture />` component enforces the same accessibility rule as `<Image />`: `alt` is required and `ImageMissingAlt` is thrown when it is `undefined`/`null`. Note the check inspects the component props, not `pictureAttributes` — putting alt on the wrapping `<picture>` element does not satisfy it.
Solutions
- Pass alt as a top-level prop: `<Picture src={hero} formats={['avif','webp']} alt="Portrait of the founder" />`
- Use `alt=""` explicitly for decorative images
- Check that wrapper-level attributes go in `pictureAttributes` but alt goes on the component itself
Example fix
// before
<Picture src={hero} formats={['avif', 'webp']} pictureAttributes={{ alt: 'Hero' }} />
// after
<Picture src={hero} formats={['avif', 'webp']} alt="Hero" pictureAttributes={{ loading: 'eager' }} /> Defensive patterns
Strategy: type-guard
Type guard
function hasAlt(props: { alt?: string | null }): boolean {
return props.alt != null;
} Prevention
- Put alt on the component, never inside pictureAttributes
- Type your data layer so image props are required at the source
- Use the same alt discipline for <Picture> as for <Image> — the check is identical
When it happens
Trigger: Rendering `<Picture src={...} formats={[...]} />` without alt; passing `alt` inside `pictureAttributes={{ alt: '...' }}` (which targets the `<picture>` wrapper) instead of as a top-level prop; destructured props where alt was not forwarded.
Common situations: Migrating from `<Image>` to `<Picture>` and misplacing attributes; data-driven components that spread `pictureAttributes` and forget the top-level alt; same CMS-missing-alt cases as `<Image>`.
Related errors
- ImageMissingAlt
- FontFamilyNotFound
- InvalidComponentArgs
- Missing `width` parameter for remote image
- [transitions]: all view transition animations, including…
AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18).
Data as JSON: /api/errors/de8dada9e6ad4427.
Report an issue: GitHub.
Appendix: 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 52e6c34790)