swc-project/swc · error · Error

Unknown statement type: ${(stmt as any).type

Error message

Unknown statement type: ${(stmt as any).type

What it means

Thrown by the legacy JavaScript `Visitor` base class that @swc/core exposes for legacy `plugin` callbacks. visitStatement() is a switch over a fixed enumeration of statement `type` strings (base ES statements plus TsEnum/TsInterface/TsModule/TsTypeAlias declarations); any statement type not in that list falls into `default` and throws `Unknown statement type: <type>`. The enumeration predates newer and less-common AST nodes, so walking modern syntax through a legacy plugin crashes instead of visiting it.

Source

Thrown at packages/core/src/Visitor.ts:515

            case "LabeledStatement":
                return this.visitLabeledStatement(stmt);
            case "ReturnStatement":
                return this.visitReturnStatement(stmt);
            case "SwitchStatement":
                return this.visitSwitchStatement(stmt);
            case "ThrowStatement":
                return this.visitThrowStatement(stmt);
            case "TryStatement":
                return this.visitTryStatement(stmt);
            case "WhileStatement":
                return this.visitWhileStatement(stmt);
            case "WithStatement":
                return this.visitWithStatement(stmt);
            case "ExpressionStatement":
                return this.visitExpressionStatement(stmt);

            default:
                throw new Error(
                    `Unknown statement type: ` + (stmt as any).type
                );
        }
    }

    visitSwitchStatement(stmt: SwitchStatement): Statement {
        stmt.discriminant = this.visitExpression(stmt.discriminant);
        stmt.cases = this.visitSwitchCases(stmt.cases);
        return stmt;
    }

    visitSwitchCases(cases: SwitchCase[]): SwitchCase[] {
        return cases.map(this.visitSwitchCase.bind(this));
    }

    visitSwitchCase(c: SwitchCase): SwitchCase {
        c.test = this.visitOptionalExpression(c.test);
        c.consequent = this.visitStatements(c.consequent);

View on GitHub (pinned to 5176682b65)

Solutions

  1. Override visitStatement in your subclass: delegate to super.visitStatement inside try/catch and return the statement untouched when the message starts with 'Unknown statement type:'
  2. Or copy the switch into your override and add a `default` that handles/returns the new node type instead of throwing
  3. Migrate off the legacy Visitor to the current plugin/visitor API, which dispatches over the full modern AST
  4. Pre-transform the input (e.g. strip newer syntax) before handing the Program to the legacy plugin

Example fix

// before
class MyVisitor extends Visitor {
    visitIdentifier(n) { /* ... */ return n; }
}
// -> Error: Unknown statement type: ...

// after
class MyVisitor extends Visitor {
    visitStatement(stmt) {
        try {
            return super.visitStatement(stmt);
        } catch (e) {
            if (e instanceof Error && e.message.startsWith('Unknown statement type:')) {
                return stmt; // pass unrecognized statements through untouched
            }
            throw e;
        }
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Dry-run the legacy visitor over a deep clone; if it throws on an unknown
// statement type, skip or reroute the plugin instead of failing the build.
const { Visitor } = require('@swc/core');
function legacyVisitorSupports(program) {
  try {
    new Visitor().visitProgram(structuredClone(program));
    return true;
  } catch (e) {
    return !(e instanceof Error && e.message.startsWith('Unknown statement type:'));
  }
}

Try / catch

class SafeVisitor extends Visitor {
  visitStatement(stmt) {
    try {
      return super.visitStatement(stmt);
    } catch (e) {
      if (e instanceof Error && e.message.startsWith('Unknown statement type:')) {
        return stmt; // pass through nodes this legacy visitor doesn't know
      }
      throw e;
    }
  }
}

Prevention

When it happens

Trigger: A legacy plugin (options.plugin using `new MyVisitor().visitProgram(program)`) walking an AST that contains a statement node type absent from the switch — a node kind introduced after this visitor was written, or a hand-built/modified AST whose statement `type` strings are misspelled or non-standard.

Common situations: Reusing an old JS plugin written for plain JS with a current @swc/core on modern syntax; prototypes that synthesize AST nodes manually; upgrading @swc/core under a plugin that used to work, exposing node types the legacy switch never knew.

Related errors


AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17). Data as JSON: /api/errors/48a46afcc1c2e42e. Report an issue: GitHub.