swc-project/swc · error

{} is not a valid expression

Error message

{} is not a valid expression

What it means

Runtime panic while building swc's `jsc.globalPassOptions` (GlobalPassOption::build in crates/swc/src/config/mod.rs). Every entry in `vars` (and every env value, wrapped as `'VALUE'` before parsing) is run through `parse_file_as_expr` with ES syntax; parse errors are emitted to the handler first, then the function panics with `{} is not a valid expression`, printing the offending source text.

Source

Thrown at crates/swc/src/config/mod.rs:2235

        fn expr(cm: &SourceMap, handler: &Handler, src: String) -> Box<Expr> {
            let fm = cm.new_source_file(FileName::Anon.into(), src);

            let mut errors = Vec::new();
            let expr = parse_file_as_expr(
                &fm,
                Syntax::Es(Default::default()),
                Default::default(),
                None,
                &mut errors,
            );

            for e in errors {
                e.into_diagnostic(handler).emit()
            }

            match expr {
                Ok(v) => v,
                _ => panic!("{} is not a valid expression", fm.src),
            }
        }

        fn mk_map(
            cm: &SourceMap,
            handler: &Handler,
            values: impl Iterator<Item = (Atom, Atom)>,
            is_env: bool,
        ) -> ValuesMap {
            let mut m = HashMap::default();

            for (k, v) in values {
                let v = if is_env {
                    format!("'{v}'")
                } else {
                    (*v).into()
                };
                let v_str = v.clone();

View on GitHub (pinned to 5176682b65)

Solutions

  1. Make each vars value a valid JS expression: quote strings (`'"production"'` or `\"production\"`) and escape embedded quotes
  2. For envs, sanitize the variable content before it reaches the config — escape or strip single quotes
  3. Pre-validate every expression string with swc_ecma_parser before handing the config to swc
  4. Remove `globalPassOptions` if the global inlining pass is not needed

Example fix

// before (.swcrc)
"globalPassOptions": { "vars": { "process.env.MSG": "it's fine" } }

// after (.swcrc)
"globalPassOptions": { "vars": { "process.env.MSG": "\"it's fine\"" } }
Defensive patterns

Strategy: validation

Validate before calling

use swc_ecma_parser::{lexer::Lexer, Parser, Syntax, EsSyntax};
use swc_common::{FileName, SourceMap, sync::Lrc};

fn is_valid_js_expr(cm: &Lrc<SourceMap>, src: &str) -> bool {
    let fm = cm.new_source_file(FileName::Anon.into(), src.to_string());
    let lexer = Lexer::new(
        Syntax::Es(EsSyntax::default()),
        Default::default(),
        &fm,
        None,
    );
    let mut p = Parser::new_from(lexer);
    p.parse_expr().is_ok()
}

// validate every globalPassOptions value before building the config
let ok = cfg.global_pass_options
    .vars
    .iter()
    .all(|(k, v)| is_valid_js_expr(&cm, v));

Prevention

When it happens

Trigger: A `.swcrc`/config `jsc.globalPassOptions.vars` value that is not a valid JS expression (e.g. `"1 +"`); or an `envs` entry whose environment variable content contains a single quote (e.g. `IT'S`) — the `'{v}'` wrapping then produces invalid JS and parsing fails.

Common situations: Inline-replacing `process.env.*` with values containing apostrophes or unbalanced quotes/braces; env vars read from user machines (locales, paths) leaking quotes into the generated expression; multiline env values.

Related errors


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