swc-project/swc · error

internal error: entered unreachable code

Error message

internal error: entered unreachable code

What it means

emit_simple_block prints the delimiters of a CSS simple block by matching the opening token against '[', '(' and '{'. Any other token reaches unreachable!(), i.e. the AST holds a SimpleBlock whose name is not a bracket token. The standard swc_css_parser cannot produce such a node, so this indicates a programmatically built or mutated AST, or a parser/codegen version mismatch.

Source

Thrown at crates/swc_css_codegen/src/lib.rs:1237

            write_str!(self, n.span, &minified);
        } else if let Some(raw) = &n.raw {
            write_str!(self, n.span, raw);
        } else {
            let value = serialize_string(&n.value);

            write_str!(self, n.span, &value);
        }
    }

    #[emitter]
    fn emit_simple_block(&mut self, n: &SimpleBlock) -> Result {
        let (starting, ending) = match n.name.token {
            Token::LBracket => ("[", "]"),
            Token::LParen => ("(", ")"),
            Token::LBrace => ("{", "}"),
            _ => {
                unreachable!();
            }
        };

        write_raw!(self, lo_span_offset!(n.span, 1), starting);

        let len = n.value.len();

        for (idx, node) in n.value.iter().enumerate() {
            match node {
                ComponentValue::ListOfComponentValues(_) | ComponentValue::Declaration(_) => {
                    if idx == 0 {
                        formatting_newline!(self);
                    }

                    increase_indent!(self);
                }
                ComponentValue::AtRule(_)
                | ComponentValue::QualifiedRule(_)

View on GitHub (pinned to 5176682b65)

Solutions

  1. If you build or mutate CSS AST yourself, normalize SimpleBlock.name.token to one of LBracket/LParen/LBrace before emitting
  2. Align all swc_css_* crates to the same version
  3. Dump the offending stylesheet/AST node, isolate it, and report to swc if it came from the parser

Example fix

// before (hand-built AST)
let block = SimpleBlock { name: ComponentValue::Ident(ident("foo")), ..Default::default() };

// after
let block = SimpleBlock { name: ComponentValue::Token(Token { span, token: Token::LBrace }), ..Default::default() };
Defensive patterns

Strategy: validation

Validate before calling

// Validate every SimpleBlock you construct/mutate before emitting
fn block_delims_ok(b: &SimpleBlock) -> bool {
    matches!(
        b.name.token,
        Token::LBracket | Token::LParen | Token::LBrace
    )
}

blocks.iter().all(block_delims_ok)

Type guard

fn is_emittable_block(b: &SimpleBlock) -> bool {
    matches!(b.name.token, Token::LBracket | Token::LParen | Token::LBrace)
}

Try / catch

let css = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
    let mut c = Codegen::new(); c.build(&stylesheet); c.get()
}));
match css {
    Ok(s) => s,
    Err(p) if panic_message(&p).contains("unreachable") => {
        // fallback: re-serialize via the parser (parse -> emit) to normalize the AST
    }
    Err(p) => std::panic::resume_unwind(p),
}

Prevention

When it happens

Trigger: Passing swc_css_ast SimpleBlock nodes constructed or altered by external code (deserializers, linters, plugins) whose name token is not LBracket/LParen/LBrace into swc_css_codegen; mixing swc_css_parser and swc_css_codegen from different releases.

Common situations: Postcss-style CSS tooling in Rust that constructs or edits AST nodes; deserializing CSS ASTs from JSON without validating token kinds; partial crate upgrades.

Related errors


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