{"record":{"id":"d69218198a6ca6ae","repo":"swc-project/swc","slug":"raw-is-not-a-valid-ecmascript-version","errorCode":null,"errorMessage":"`{raw}` is not a valid ecmascript version","messagePattern":"`(.+?)` is not a valid ecmascript version","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/swc_ecma_minifier/src/option/terser.rs","lineNumber":464,"sourceCode":"    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            TerserEcmaVersion::Num(value) => value.fmt(f),\n            TerserEcmaVersion::Str(value) => value.fmt(f),\n        }\n    }\n}\n\nimpl From<TerserEcmaVersion> for EsVersion {\n    fn from(value: TerserEcmaVersion) -> Self {\n        let raw = value.to_string();\n        let normalized = match value {\n            TerserEcmaVersion::Num(value) => normalize_terser_ecma_num(value),\n            TerserEcmaVersion::Str(value) => match value.parse::<usize>() {\n                Ok(value) => normalize_terser_ecma_num(value),\n                Err(..) => Some(value),\n            },\n        }\n        .unwrap_or_else(|| panic!(\"`{raw}` is not a valid ecmascript version\"));\n\n        serde_json::from_value(Value::String(normalized))\n            .unwrap_or_else(|_| panic!(\"`{raw}` is not a valid ecmascript version\"))\n    }\n}\n\nfn normalize_terser_ecma_num(value: usize) -> Option<String> {\n    match value {\n        3 | 5 => Some(format!(\"es{value}\")),\n        6 => Some(String::from(\"es2015\")),\n        2015.. => Some(format!(\"es{value}\")),\n        _ => None,\n    }\n}\n\nimpl From<TerserTopRetainOption> for Vec<Atom> {\n    fn from(v: TerserTopRetainOption) -> Self {\n        match v {","sourceCodeStart":446,"sourceCodeEnd":482,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_ecma_minifier/src/option/terser.rs#L446-L482","documentation":"Converting a terser ecma version to EsVersion first normalizes the numeric value via normalize_terser_ecma_num: only 3, 5, 6 (mapped to es2015), and full years 2015+ are valid. Any other number (0, 1, 2, 4, 7, 8, 9, 1999, ...) returns None and panics with '`{raw}` is not a valid ecmascript version'. String values that parse as a number go through the same path.","triggerScenarios":"compress option ecma set to 7, 8, or 9 (or \"7\"): position between ES6 and the year-based scheme (es2015+); ecma: 4 or 0; any pre-2015 year other than the special-cased 3/5/6.","commonSituations":"Guessing that terser accepts 7/8/9 shorthands (it only accepts 5, 2015+, or 6-as-2015), porting configs from tools that use plain engine version numbers, programmatic config generation inserting engine major versions.","solutions":["Use an accepted numeric form: 5, 6, or a full year such as 2015, 2020","Prefer the canonical string form (\"es2015\", \"es2020\") to make intent explicit and avoid the numeric special cases","Validate the ecma field against the accepted set at config load time"],"exampleFix":"// before\n{ \"compress\": { \"ecma\": 7 } } // panic: `7` is not a valid ecmascript version\n\n// after\n{ \"compress\": { \"ecma\": 2015 } }","handlingStrategy":"validation","validationCode":"// JS: accepted numeric ecma values\nconst okNum = n => [3, 5, 6].includes(n) || (Number.isInteger(n) && n >= 2015);\nif (!okNum(ecma)) throw new Error(`ecma ${ecma} is not valid; use 5, 6, or a year >= 2015`);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use full years (2015+) in configs instead of engine major versions","Centralize ecma validation in one config helper shared across builds","Remember 6 maps to es2015; 7-9 do not exist in the terser scheme"],"tags":["minifier","terser","ecma-version","config","validation"],"backgroundTag":"invalid-ecma-version","analyzedSha":"5176682b65416c6b5de6b47379ae1588ea3ecb3f","analyzedAt":"2026-08-17T16:16:52.067Z","contentChangedAt":"2026-08-17T16:16:52.067Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}