withastro/astro · error · AstroError
FileParserNotFound
FileParserNotFound
Error message
No parser was found for '${fileName}'. Pass a parser function (e.g. `parser: csv`) to the `file` loader. What it means
The file() loader has built-in parsers for .json, .yml/.yaml, and .toml only (detected case-sensitively from the extension). For any other extension you must pass a `parser` function in options; otherwise it throws FileParserNotFound at config-load time.
Solutions
- Pass a parser: `file('data/products.csv', { parser: (text) => Papa.parse(text, { header: true }).data })`.
- Rename the file to use a supported lowercase extension (.json, .yml, .yaml, .toml) if the format already matches.
- For odd extensions wrapping standard formats (e.g. `.jsonc`), supply the matching parser explicitly: `parser: JSON.parse`.
Example fix
// before
const Products = defineCollection({ loader: file('data/products.csv') });
// after
import Papa from 'papaparse';
const Products = defineCollection({
loader: file('data/products.csv', {
parser: (text) => Papa.parse(text, { header: true }).data,
}),
}); Defensive patterns
Strategy: validation
Validate before calling
import { extname } from 'node:path';
const BUILTIN = ['.json', '.yml', '.yaml', '.toml'];
function needsParser(fileName: string): boolean {
return !BUILTIN.includes(extname(fileName).toLowerCase());
}
if (needsParser('data/products.csv')) {
// pass { parser: ... } or rename the file
} Type guard
const hasBuiltinParser = (fileName: string): boolean => ['.json', '.yml', '.yaml', '.toml'].includes(extname(fileName).toLowerCase());
Prevention
- Use lowercase file extensions — the extension check is case-sensitive.
- For CSV, wire a parser (e.g. papaparse) once in a shared helper instead of per collection.
When it happens
Trigger: `file('data/products.csv')` with no options; also `file('DATA.JSON')` — the extension check is case-sensitive, so an uppercase `.JSON` finds no built-in parser either.
Common situations: Loading CSV, XML, or INI data files; files with uppercase extensions; teams assuming file() can read any text format out of the box.
Related errors
- ** ** contains multiple entries with the same slug: ` `…
- DuplicateContentEntrySlugError
- FileGlobNotSupported
- No items found in
- A content collection is defined with legacy features (e.g…
AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18).
Data as JSON: /api/errors/c16b487525174a5a.
Report an issue: GitHub.
Appendix: source
Thrown at packages/astro/src/content/loaders/file.ts:50
}
let parse: ((text: string) => any) | null = null;
const ext = fileName.split('.').at(-1);
if (ext === 'json') {
parse = JSON.parse;
} else if (ext === 'yml' || ext === 'yaml') {
parse = (text) =>
yaml.load(text, {
filename: fileName,
});
} else if (ext === 'toml') {
parse = toml.parse;
}
if (options?.parser) parse = options.parser;
if (parse === null) {
throw new AstroError({
...FileParserNotFound,
message: FileParserNotFound.message(fileName),
});
}
async function syncData(
filePath: string,
{ logger, parseData, store, config, collection }: LoaderContext,
) {
let data: Array<Record<string, unknown>> | Record<string, Record<string, unknown>>;
try {
const contents = await fs.readFile(filePath, 'utf-8');
data = await parse!(contents);
} catch (error: any) {
logger.error(`Error reading data from ${fileName}`);
logger.debug(error.message);
return;View on GitHub (pinned to 52e6c34790)