{"record":{"id":"3c7e9c0b556171df","repo":"swc-project/swc","slug":"infinite-loop-detected-current-pass","errorCode":null,"errorMessage":"Infinite loop detected (current pass = {})\n{}","messagePattern":"Infinite loop detected \\(current pass = (.+?)\\)\n(.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/swc_ecma_minifier/src/compress/mod.rs","lineNumber":139,"sourceCode":"        // );\n    }\n\n    /// Optimize a module. `N` can be [Module] or [FnExpr].\n    fn optimize_unit(&mut self, n: &mut Program) {\n        if self.options.passes != 0 && self.options.passes < self.pass {\n            #[cfg(debug_assertions)]\n            {\n                let done = dump(&*n, false);\n                debug!(\"===== Done =====\\n{}\", done);\n            }\n            return;\n        }\n\n        // This exists to prevent hanging.\n        if self.pass > 200 {\n            let code = force_dump_program(n);\n\n            panic!(\n                \"Infinite loop detected (current pass = {})\\n{}\",\n                self.pass, code\n            );\n        }\n\n        #[cfg(all(debug_assertions, feature = \"debug\"))]\n        let start = {\n            let start = force_dump_program(n);\n            #[cfg(debug_assertions)]\n            debug!(\"===== Start =====\\n{}\", start);\n            start\n        };\n\n        {\n            let mut visitor = pure_optimizer(\n                self.options,\n                self.marks,\n                PureOptimizerConfig {","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_ecma_minifier/src/compress/mod.rs#L121-L157","documentation":"The minifier repeats optimization passes until the program stops changing. A guard panics once self.pass exceeds 200 because the output keeps mutating every pass (non-convergence or oscillation between two rewrites), which would otherwise hang the build forever. The panic embeds a dump of the current program via force_dump_program to make the offending code visible.","triggerScenarios":"Running compress with an option combination where one pass rewrites code that a later pass rewrites back (fixed point never reached); a convergence regression in a specific swc_ecma_minifier version; extremely high user-configured `passes` values interacting with an oscillating transform.","commonSituations":"Aggressive terser-style compress options in .swcrc or jsc.minify.compress, minifying machine-generated or vendored bundles, upgrading swc_core and hitting a minifier regression, running with defaults:true plus extra toggles.","solutions":["Upgrade swc_ecma_minifier/swc_core: non-convergence regressions are treated as bugs and fixed quickly","Cap `compress.passes` to a small number (e.g. 2) so the loop terminates before the guard trips","Disable the transforms most often involved in oscillation (collapse_vars, inline/sequences, unsafe options) to break the cycle","Save the dumped program from the panic message and file a minimized SWC issue"],"exampleFix":"// .swcrc - before\n{\n  \"jsc\": {\n    \"minify\": {\n      \"compress\": { \"defaults\": true, \"collapse_vars\": true, \"inline\": 3 }\n    }\n  }\n}\n\n// .swcrc - after\n{\n  \"jsc\": {\n    \"minify\": {\n      \"compress\": { \"defaults\": true, \"passes\": 2, \"collapse_vars\": false }\n    }\n  }\n}","handlingStrategy":"fallback","validationCode":"// JS: cap passes before invoking the minifier\nconst compress = { ...opts.compress, passes: Math.min(opts.compress?.passes ?? 2, 2) };","typeGuard":null,"tryCatchPattern":"use std::panic::{catch_unwind, AssertUnwindSafe};\nlet out = catch_unwind(AssertUnwindSafe(|| minify(code, &opts)));\nif out.is_err() {\n    // fallback: retry once with a conservative preset that converges\n    let mut safe = opts.clone();\n    safe.compress = CompressOptions::default();\n    out = catch_unwind(AssertUnwindSafe(|| minify(code, &safe)));\n}\n// if still failing, ship the unminified source and report the dumped program","preventionTips":["Keep compress.passes small (1-3); convergence issues amplify with passes","Pin swc_ecma_minifier versions you have fuzz-tested against your bundle corpus","Cache minified artifacts so a regression cannot wedge CI repeatedly"],"tags":["minifier","infinite-loop","hang-guard","panic","compress-options"],"backgroundTag":"optimizer-non-convergence","analyzedSha":"5176682b65416c6b5de6b47379ae1588ea3ecb3f","analyzedAt":"2026-08-17T16:16:52.067Z","contentChangedAt":"2026-08-17T16:16:52.067Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}