prettier/prettier · error · UnexpectedNodeError
Unexpected specifier node type: ${node.type}.
Error message
Unexpected specifier node type: ${node.type}. What it means
`printModuleSpecifiers` (src/language-js/print/module.js:191) iterates import/export specifiers and only handles ImportSpecifier, ImportDefaultSpecifier, ImportNamespaceSpecifier, ExportSpecifier, ExportDefaultSpecifier, and ExportNamespaceSpecifier. Any other specifier node type triggers `UnexpectedNodeError(node, "specifier")`. Like the JSX case it is `c8`-ignored as unreachable under normal parsing.
Source
Thrown at src/language-js/print/module.js:191
const groupedSpecifiers = [];
path.each(() => {
const specifierType = path.node.type;
if (
specifierType === "ExportNamespaceSpecifier" ||
specifierType === "ExportDefaultSpecifier" ||
specifierType === "ImportNamespaceSpecifier" ||
specifierType === "ImportDefaultSpecifier"
) {
standaloneSpecifiers.push(print());
} else if (
specifierType === "ExportSpecifier" ||
specifierType === "ImportSpecifier"
) {
groupedSpecifiers.push(print());
} else {
/* c8 ignore next 3 */
throw new UnexpectedNodeError(node, "specifier");
}
}, "specifiers");
parts.push(join(", ", standaloneSpecifiers));
if (groupedSpecifiers.length > 0) {
if (standaloneSpecifiers.length > 0) {
parts.push(", ");
}
const canBreak =
groupedSpecifiers.length > 1 ||
standaloneSpecifiers.length > 0 ||
node.specifiers.some((node) => hasComment(node));
if (canBreak) {
parts.push(
group([View on GitHub (pinned to 315f281982)
Solutions
- Update Prettier (and its bundled parser) to a version that supports the ESM syntax you use.
- If you author a parser plugin, map specifiers to one of the six recognized types.
- Report the specifier type with a minimal reproducible example.
- Temporarily avoid formatting the affected import/export statement (e.g. // prettier-ignore).
Defensive patterns
Strategy: try-catch
Validate before calling
const KNOWN_SPECIFIERS = new Set(["ImportSpecifier","ImportDefaultSpecifier","ImportNamespaceSpecifier","ExportSpecifier","ExportDefaultSpecifier","ExportNamespaceSpecifier"]);
function specifiersLookValid(ast) {
for (const decl of ast?.program?.body ?? []) {
for (const spec of decl.specifiers ?? []) {
if (!KNOWN_SPECIFIERS.has(spec.type)) return false;
}
}
return true;
} Type guard
function isKnownSpecifier(node) { return node?.type && KNOWN_SPECIFIERS.has(node.type); } Try / catch
try {
await prettier.format(src, { parser: "babel" });
} catch (e) {
if (e.name === "UnexpectedNodeError" && /specifier/.test(e.message)) {
// log + skip formatting this file
} else throw e;
} Prevention
- Avoid AST transforms that invent specifier types.
- Match parser and Prettier versions for new ESM features.
When it happens
Trigger: A custom parser/transform introduces a specifier type outside the six known ones; experimental ECMAScript import syntax (e.g. import attributes) producing a specifier shape Prettier does not recognize; a plugin that rewrites import statements into non-standard specifier nodes.
Common situations: Bleeding-edge ESM syntax; a code-mod or plugin that mutates specifier AST nodes; parser and Prettier version skew.
Related errors
- Unexpected JSX node type: ${node.type}.
- Unexpected TypeScript node type: ${node.type}.
- Couldn't find plugin for AST format "${astFormat}".
- Unexpected node has no left side.
- Unexpected PostCSS node type: ${node.type}.
AI-assisted analysis of prettier/prettier@315f281982 (2026-08-03).
Data as JSON: /data/errors/d8b7f211851e0627.json.
Report an issue: GitHub.