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

  1. Update Prettier (and its bundled parser) to a version that supports the ESM syntax you use.
  2. If you author a parser plugin, map specifiers to one of the six recognized types.
  3. Report the specifier type with a minimal reproducible example.
  4. 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

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


AI-assisted analysis of prettier/prettier@315f281982 (2026-08-03). Data as JSON: /data/errors/d8b7f211851e0627.json. Report an issue: GitHub.