withastro/astro · error · Error
File path must be relative to the site root. Got
Error message
File path must be relative to the site root. Got: ${filePath} What it means
The data store requires `filePath` on `set()` to be a path relative to the project root, because the store is serialized and shared across machines. A filePath starting with `/` (an absolute path) is rejected with a plain Error so machine-specific paths never get persisted.
Solutions
- Relativize against the project root before setting: compute `relative(fileURLToPath(config.root), filePath)` and convert separators to `/`.
- Or omit `filePath` if you do not need file-tracking (watcher/HMR) features for these entries.
- Use the same convention as built-in loaders: POSIX-style relative path like `src/content/blog/post.md`.
Example fix
// before
import { fileURLToPath } from 'node:url';
store.set({ id, data, filePath: fileURLToPath(fileUrl) }); // absolute
// after
import { relative, sep } from 'node:path';
import { fileURLToPath } from 'node:url';
const filePath = relative(fileURLToPath(config.root), fileURLToPath(fileUrl)).split(sep).join('/');
store.set({ id, data, filePath }); Defensive patterns
Strategy: validation
Validate before calling
import { relative, sep } from 'node:path';
import { fileURLToPath } from 'node:url';
function toRootRelative(root: URL, filePath: string): string {
const rel = relative(fileURLToPath(root), filePath);
if (rel.startsWith('..')) throw new Error(`filePath escapes project root: ${filePath}`);
return rel.split(sep).join('/');
}
store.set({ id, data, filePath: toRootRelative(config.root, absolutePath) }); Type guard
const isRootRelativePosixPath = (p: string): boolean =>
!p.startsWith('/') && !p.includes('\\') && !p.startsWith('..'); Prevention
- Always relativize against config.root in custom loaders; never persist fileURLToPath output.
- Use forward slashes so the store stays portable to Windows.
When it happens
Trigger: A custom loader passing `fileURLToPath(entryUrl)` or `path.resolve(...)` output directly: `store.set({ id, data, filePath: '/home/me/project/src/content/a.md' })`.
Common situations: Custom loaders built from Node examples that use absolute paths; porting code that logged absolute paths for debugging and then fed them back into the store.
Related errors
- ID must be a non-empty string
- [content] Could not read the chunked data store at
- data store cleared (force)
- A content collection is defined with legacy features (e.g…
- An error was encountered while creating the JSON schema for…
AI-assisted analysis of withastro/astro@e294953aa8 (2026-08-18).
Data as JSON: /api/errors/94beaa003cdd7211.
Report an issue: GitHub.
Appendix: source
Thrown at packages/astro/src/content/mutable-data-store.ts:456
const src = val.replace(IMAGE_IMPORT_PREFIX, '');
foundAssets.add(src);
recordImageImport(ctx.path.map((segment) => segment as string | number));
ctx.update(src);
}
});
const entry: DataEntry = {
id,
data,
};
// We do it like this so we don't waste space stringifying
// the fields if they are not set
if (body) {
entry.body = body;
}
if (filePath) {
if (filePath.startsWith('/')) {
throw new Error(`File path must be relative to the site root. Got: ${filePath}`);
}
entry.filePath = filePath;
}
if (foundAssets.size) {
entry.assetImports = Array.from(foundAssets);
this.addAssetImports(entry.assetImports, filePath);
}
if (imageImports.length) {
entry.imageImports = imageImports;
}
if (digest) {
entry.digest = digest;
}
if (rendered) {
entry.rendered = rendered;View on GitHub (pinned to e294953aa8)