withastro/astro · error · AstroError
ImageNotFound
ImageNotFound
Error message
Could not find requested image `${id}`. Does it exist? What it means
During build, Astro's assets plugin resolves imported images and calls `emitImageMetadata(id)` to read their dimensions. If that returns nothing — almost always because the file does not exist on disk — the plugin throws ImageNotFound ('Could not find requested image `${id}`') instead of letting Vite produce a confusing resolution error further down.
Solutions
- Check the exact `id` in the error message against the filesystem: does the file exist at that path with that exact casing
- Fix the import path or restore/rename the file so they match (mind case sensitivity for CI on Linux)
- If the import is generated (content collections, glob), regenerate the references or make the generator skip missing files
Example fix
// before import hero from '../images/Hero.png'; // file is hero.png // after import hero from '../images/hero.png';
Defensive patterns
Strategy: validation
Validate before calling
// verify every imported image exists before build (case-sensitive!)
import { existsSync } from 'node:fs';
import { join, dirname } from 'node:path';
function assertImportExists(importer: string, spec: string): void {
if (spec.startsWith('.')) {
const target = join(dirname(importer), spec);
if (!existsSync(target)) {
throw new Error(`Missing image: ${spec} imported from ${importer}`);
}
}
} Try / catch
try {
const meta = await emitImageMetadata(id);
if (!meta) throw Object.assign(new Error(`Image not found: ${id}`), { code: 'ImageNotFound' });
} catch (err) {
if ((err as { code?: string }).code === 'ImageNotFound') {
// fail fast with the exact path so CI output is actionable
process.exitCode = 1;
}
throw err;
} Prevention
- Develop with case-sensitive path checking (Linux CI or a lint rule) to catch Hero.png vs hero.png
- Codemod imports when renaming asset files instead of hand-editing
When it happens
Trigger: `import hero from '../images/hero.png'` where the file was deleted, renamed, or the relative path is wrong; casing mismatch on case-sensitive CI filesystems (Hero.png vs hero.png) that works locally on macOS/Windows; imports generated from content collections referencing removed files.
Common situations: Renaming assets in a PR while another branch still imports old names; git not tracking empty directories or lfs-filtered files after fresh clones; Windows-local works but Linux CI fails on path case; scaffolding templates referencing optional images.
Related errors
- NoImageMetadata
- ⚠️ Astro could not optimize image
- ⚠️ Astro expected an SVG for
- FailedToFetchRemoteImageDimensions
- GetImageNotUsedOnServer
AI-assisted analysis of withastro/astro@e294953aa8 (2026-08-18).
Data as JSON: /api/errors/2036212c84a2cc1d.
Report an issue: GitHub.
Appendix: source
Thrown at packages/astro/src/assets/vite-plugin-assets.ts:400
if (id !== removeQueryString(id)) {
// If our import has any query params, we'll let Vite handle it, nonetheless we'll make sure to not delete it
// See https://github.com/withastro/astro/issues/8333
globalThis.astroAsset.referencedImages.add(removeQueryString(id));
return;
}
// If the requested ID doesn't end with a valid image extension, we'll let Vite handle it
if (!assetRegexEnds.test(id)) {
return;
}
const fileEmitter = shouldEmitFile
? (opts: Parameters<typeof this.emitFile>[0]) => emitClientAsset(this as any, opts)
: undefined;
const imageMetadata = await emitImageMetadata(id, fileEmitter);
if (!imageMetadata) {
throw new AstroError({
...AstroErrorData.ImageNotFound,
message: AstroErrorData.ImageNotFound.message(id),
});
}
// We can only reliably determine if an image is used on the server, as we need to track its usage throughout the entire build.
// Since you cannot use image optimization on the client anyway, it's safe to assume that if the user imported
// an image on the client, it should be present in the final build.
if (isAstroServerEnvironment(this.environment)) {
// For SVGs imported directly (not via content collections), create a full
// component that can be rendered inline. For content collection SVGs, the
// component is reconstructed later in content/runtime.ts from __svgData
// embedded in the metadata, avoiding a server-runtime import here that
// would create a circular dependency when combined with TLA.
if (id.endsWith('.svg')) {
const contents = await fs.promises.readFile(imageMetadata.fsPath, {
encoding: 'utf8',
});View on GitHub (pinned to e294953aa8)