withastro/astro · error · AstroError
LocalImageUsedWrongly
LocalImageUsedWrongly
Error message
`Image`'s and `getImage`'s `src` parameter must be an imported image or a URL, it cannot be a string filepath. Received `${imageFilePath}`. What it means
In `verifyOptions()` (packages/astro/src/assets/services/service.ts:164), a string `src` that is neither remote nor starts with `/` — or starts with `/@fs/` — is treated as a filesystem path and rejected with `LocalImageUsedWrongly`. String paths bypass Astro's build-time image pipeline (no metadata, no hashing), so they are disallowed: local images must be ESM-imported so their dimensions and content are known.
Solutions
- Import the image and pass the metadata object: `import hero from '../assets/hero.png'` then `src={hero}` (dimensions come from the file).
- If the file lives in `public/`, reference it with a root-relative URL (`/hero.png`) — and note public images are served as-is, so `<img>` or explicit dimensions may fit better.
- For truly remote images, use the full URL starting with a protocol.
Example fix
// before
<Image src="/@fs/home/me/app/src/assets/hero.png" alt="Hero" width={800} height={600} />
// after
import hero from '../assets/hero.png';
<Image src={hero} alt="Hero" width={800} height={600} /> Defensive patterns
Strategy: type-guard
Validate before calling
const isLocalFilePath = (src: string): boolean =>
src.startsWith('/@fs/') || (!src.startsWith('http') && !src.startsWith('/'));
if (typeof src === 'string' && isLocalFilePath(src)) {
throw new Error(`Import the image instead of passing a filepath: ${src}`);
} Type guard
function isImportableLocalPath(src: string): boolean {
// usable as a string src only when public-root relative or remote
return src.startsWith('http') || src.startsWith('/');
}
const needsEsmImport = (src: string): boolean => src.startsWith('/@fs/') || (!needsNoImport(src));
function needsNoImport(src: string): boolean {
return src.startsWith('http') || src.startsWith('/') && !src.startsWith('/@fs/');
} Prevention
- Codemod existing <img> tags to ESM imports when adopting <Image>.
- Never reference project files by string path in image components; only public/ assets with root-relative URLs.
When it happens
Trigger: `<Image src="../assets/hero.png" ...>`, `src="src/assets/hero.png"`, or `src="/@fs/home/me/app/src/assets/hero.png"` — any filesystem-ish string instead of an import or a remote URL.
Common situations: Porting plain `<img>` markup to `<Image>`; UI-framework components (React islands) that reference files by path; copy-pasting the `/@fs/` URLs visible in devtools during development.
Related errors
- ExpectedImage
- ExpectedNotESMImage
- MissingImageDimension
- UnsupportedImageFormat
- ⚠️ Astro could not optimize image
AI-assisted analysis of withastro/astro@e294953aa8 (2026-08-18).
Data as JSON: /api/errors/8fd6d46e9be68dd6.
Report an issue: GitHub.
Appendix: source
Thrown at packages/astro/src/assets/services/service.ts:175
// `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),
});
}
// For remote images, width and height are explicitly required as we can't infer them from the file
let missingDimension: 'width' | 'height' | 'both' | undefined;
if (!options.width && !options.height) {
missingDimension = 'both';
} else if (!options.width && options.height) {
missingDimension = 'width';
} else if (options.width && !options.height) {
missingDimension = 'height';
}
if (missingDimension) {
throw new AstroError({
...AstroErrorData.MissingImageDimension,View on GitHub (pinned to e294953aa8)