withastro/astro · error · AstroError
UnknownContentCollectionError
UnknownContentCollectionError
Error message
Unexpected error reading entry ${JSON.stringify(fileId)}. What it means
vite-plugin-content-imports generates a module per entry when astro:content imports are requested in dev or build. Before emitting the module it reads the raw entry file; a read failure is wrapped as UnknownContentCollectionError with the underlying stack attached.
Solutions
- Restore the file or stop importing it, then reload — the dev server regenerates entry modules on demand.
- Restart the dev server to clear the stale module graph.
- Verify the path printed in the error exists and is readable.
- If it recurs on every save, exclude src/content from antivirus scanning or tune watcher debounce.
Defensive patterns
Strategy: retry
Validate before calling
// Guard code that imports entries by id: confirm the file exists first
import { existsSync } from 'node:fs';
import { join } from 'node:path';
function assertEntryFile(collectionDir, id) {
const p = join(collectionDir, id);
if (!existsSync(p)) throw new Error(`entry file gone: ${p}`);
} Try / catch
// In dev, a reload usually regenerates the module after file churn
try {
await import('astro:content');
} catch (e) {
if (e instanceof Error && e.message.startsWith('Unexpected error reading entry')) {
// restart/reload dev server, then retry the import
throw new Error('entry file unreadable — restore it and reload the dev server', { cause: e });
}
throw e;
} Prevention
- Rename or delete content entries only after closing pages that import them, or expect a transient error until reload.
- Restart astro dev after bulk content moves.
- Keep antivirus/watcher interference away from src/content on Windows.
When it happens
Trigger: The dev server holds a module for an entry that was just deleted or moved while an open page still imports it; file permissions or locking (antivirus on Windows); partial writes racing the watcher.
Common situations: Renaming/removing content entries while astro dev runs; editor atomic saves; monorepo watchers firing on half-written files; paths with characters the filesystem rejects.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- UnknownFilesystemError
- ▶ vite.server.fs.strict has been disabled! Files on your…
- Content config not loaded
- Error when reading content directory
- Failed to write lock file
AI-assisted analysis of withastro/astro@e294953aa8 (2026-08-18).
Data as JSON: /api/errors/9f89eac55ec2d9b6.
Report an issue: GitHub.
Appendix: source
Thrown at packages/astro/src/content/vite-plugin-content-imports.ts:348
};
return dataEntryModule;
}
// Shared logic for `getContentEntryModule` and `getDataEntryModule`
// Extracting to a helper was easier that conditionals and generics :)
async function getEntryModuleBaseInfo<TEntryType extends ContentEntryType | DataEntryType>({
fileId,
entryConfigByExt,
contentDir,
fs,
}: GetEntryModuleParams<TEntryType>) {
const contentConfig = await getContentConfigFromGlobal();
let rawContents;
try {
rawContents = await fs.promises.readFile(fileId, 'utf-8');
} catch (e) {
throw new AstroError({
...AstroErrorData.UnknownContentCollectionError,
message: `Unexpected error reading entry ${JSON.stringify(fileId)}.`,
stack: e instanceof Error ? e.stack : undefined,
});
}
const fileExt = extname(fileId);
const entryConfig = entryConfigByExt.get(fileExt);
if (!entryConfig) {
throw new AstroError({
...AstroErrorData.UnknownContentCollectionError,
message: `No parser found for data entry ${JSON.stringify(
fileId,
)}. Did you apply an integration for this file type?`,
});
}
const entry = pathToFileURL(fileId);
const collection = getEntryCollectionName({ entry, contentDir });View on GitHub (pinned to e294953aa8)