{"record":{"id":"8fd6d46e9be68dd6","repo":"withastro/astro","slug":"localimageusedwrongly","errorCode":"LocalImageUsedWrongly","errorMessage":"`Image`'s and `getImage`'s `src` parameter must be an imported image or a URL, it cannot be a string filepath. Received `${imageFilePath}`.","messagePattern":"`Image`'s and `getImage`'s `src` parameter must be an imported image or a URL, it cannot be a string filepath\\. Received `(.+?)`\\.","errorType":"exception","errorClass":"AstroError","httpStatus":null,"severity":"error","filePath":"packages/astro/src/assets/services/service.ts","lineNumber":175,"sourceCode":"\t// `src` is missing or is `undefined`.\n\tif (!options.src || (!isRemoteImage(options.src) && !isESMImportedImage(options.src))) {\n\t\tthrow new AstroError({\n\t\t\t...AstroErrorData.ExpectedImage,\n\t\t\tmessage: AstroErrorData.ExpectedImage.message(\n\t\t\t\tJSON.stringify(options.src),\n\t\t\t\ttypeof options.src,\n\t\t\t\tJSON.stringify(options, (_, v) => (v === undefined ? null : v)),\n\t\t\t),\n\t\t});\n\t}\n\n\tif (!isESMImportedImage(options.src)) {\n\t\t// User passed an `/@fs/` path or a filesystem path instead of the full image.\n\t\tif (\n\t\t\toptions.src.startsWith('/@fs/') ||\n\t\t\t(!isRemotePath(options.src) && !options.src.startsWith('/'))\n\t\t) {\n\t\t\tthrow new AstroError({\n\t\t\t\t...AstroErrorData.LocalImageUsedWrongly,\n\t\t\t\tmessage: AstroErrorData.LocalImageUsedWrongly.message(options.src),\n\t\t\t});\n\t\t}\n\n\t\t// For remote images, width and height are explicitly required as we can't infer them from the file\n\t\tlet missingDimension: 'width' | 'height' | 'both' | undefined;\n\t\tif (!options.width && !options.height) {\n\t\t\tmissingDimension = 'both';\n\t\t} else if (!options.width && options.height) {\n\t\t\tmissingDimension = 'width';\n\t\t} else if (options.width && !options.height) {\n\t\t\tmissingDimension = 'height';\n\t\t}\n\n\t\tif (missingDimension) {\n\t\t\tthrow new AstroError({\n\t\t\t\t...AstroErrorData.MissingImageDimension,","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/withastro/astro/blob/e294953aa8aadd98d5be92e60a03037b05dbdfd4/packages/astro/src/assets/services/service.ts#L157-L193","documentation":"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.","triggerScenarios":"`<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.","commonSituations":"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.","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."],"exampleFix":"// before\n<Image src=\"/@fs/home/me/app/src/assets/hero.png\" alt=\"Hero\" width={800} height={600} />\n\n// after\nimport hero from '../assets/hero.png';\n<Image src={hero} alt=\"Hero\" width={800} height={600} />","handlingStrategy":"type-guard","validationCode":"const isLocalFilePath = (src: string): boolean =>\n  src.startsWith('/@fs/') || (!src.startsWith('http') && !src.startsWith('/'));\n\nif (typeof src === 'string' && isLocalFilePath(src)) {\n  throw new Error(`Import the image instead of passing a filepath: ${src}`);\n}","typeGuard":"function isImportableLocalPath(src: string): boolean {\n  // usable as a string src only when public-root relative or remote\n  return src.startsWith('http') || src.startsWith('/');\n}\nconst needsEsmImport = (src: string): boolean => src.startsWith('/@fs/') || (!needsNoImport(src));\nfunction needsNoImport(src: string): boolean {\n  return src.startsWith('http') || src.startsWith('/') && !src.startsWith('/@fs/');\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["images","image-component","esm-import"],"backgroundTag":"file-path-instead-of-import","analyzedSha":"e294953aa8aadd98d5be92e60a03037b05dbdfd4","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}