{"record":{"id":"94beaa003cdd7211","repo":"withastro/astro","slug":"file-path-must-be-relative-to-the-site-root-got","errorCode":null,"errorMessage":"File path must be relative to the site root. Got: ${filePath}","messagePattern":"File path must be relative to the site root\\. Got: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/astro/src/content/mutable-data-store.ts","lineNumber":371,"sourceCode":"\t\t\t\tforEach(data, (_, val) => {\n\t\t\t\t\tif (typeof val === 'string' && val.startsWith(IMAGE_IMPORT_PREFIX)) {\n\t\t\t\t\t\tconst src = val.replace(IMAGE_IMPORT_PREFIX, '');\n\t\t\t\t\t\tfoundAssets.add(src);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tconst entry: DataEntry = {\n\t\t\t\t\tid,\n\t\t\t\t\tdata,\n\t\t\t\t};\n\t\t\t\t// We do it like this so we don't waste space stringifying\n\t\t\t\t// the fields if they are not set\n\t\t\t\tif (body) {\n\t\t\t\t\tentry.body = body;\n\t\t\t\t}\n\t\t\t\tif (filePath) {\n\t\t\t\t\tif (filePath.startsWith('/')) {\n\t\t\t\t\t\tthrow new Error(`File path must be relative to the site root. Got: ${filePath}`);\n\t\t\t\t\t}\n\t\t\t\t\tentry.filePath = filePath;\n\t\t\t\t}\n\n\t\t\t\tif (foundAssets.size) {\n\t\t\t\t\tentry.assetImports = Array.from(foundAssets);\n\t\t\t\t\tthis.addAssetImports(entry.assetImports, filePath);\n\t\t\t\t}\n\n\t\t\t\tif (digest) {\n\t\t\t\t\tentry.digest = digest;\n\t\t\t\t}\n\t\t\t\tif (rendered) {\n\t\t\t\t\tentry.rendered = rendered;\n\t\t\t\t}\n\t\t\t\tif (deferredRender) {\n\t\t\t\t\tentry.deferredRender = deferredRender;\n\t\t\t\t\tif (filePath) {","sourceCodeStart":353,"sourceCodeEnd":389,"githubUrl":"https://github.com/withastro/astro/blob/d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca/packages/astro/src/content/mutable-data-store.ts#L353-L389","documentation":"Thrown as a plain Error (no AstroError code) from the scoped store's set() method when the supplied filePath begins with '/'. The store expects paths relative to the site root (no leading slash); absolute paths would break module resolution and the generated import map.","triggerScenarios":"A loader calls context.store.set({ id, data, filePath: '/src/content/x.md' }) — passing an absolute or leading-slash path instead of a relative one.","commonSituations":"Using path.resolve() or fileURLToPath() without converting to a project-relative form; copying an OS-absolute path into filePath; loader code that prefixes '/' to normalize.","solutions":["Pass a relative path (no leading slash) — use posixRelative(root, absolutePath) to convert.","If you have an absolute path, strip the project root prefix before passing it.","Replicate the pattern used by the built-in file/glob loaders (they call posixRelative)."],"exampleFix":"// before\nconst filePath = '/src/content/posts/a.md';\ncontext.store.set({ id, data, filePath });\n// after\nimport { posixRelative } from 'astro/content/utils';\nconst filePath = posixRelative(config.root, absolutePath);\ncontext.store.set({ id, data, filePath });","handlingStrategy":"validation","validationCode":"import { posix } from 'node:path';\nfunction toRelativeFilePath(p: string) {\n  if (p.startsWith('/')) throw new Error(`filePath must be relative: ${p}`);\n  return posix.normalize(p);\n}","typeGuard":"const isRelativeFilePath = (p: string) => !p.startsWith('/');","tryCatchPattern":null,"preventionTips":["Convert absolute paths with posixRelative(root, abs) before passing to store.set.","Never prefix filePath with '/'; mirrors the built-in loaders' convention.","Add a lint rule or wrapper that rejects leading-slash filePath."],"tags":["content-collections","data-store","loader","path","validation"],"backgroundTag":null,"analyzedSha":"d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca","analyzedAt":"2026-08-12T13:37:29.035Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}