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

  1. Relativize against the project root before setting: compute `relative(fileURLToPath(config.root), filePath)` and convert separators to `/`.
  2. Or omit `filePath` if you do not need file-tracking (watcher/HMR) features for these entries.
  3. 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

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


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)