{"record":{"id":"71b630590acc9378","repo":"swc-project/swc","slug":"you-should-perform-this-operation-in-the-closure-p","errorCode":null,"errorMessage":"You should perform this operation in the closure passed to `set` of {}::{}","messagePattern":"You should perform this operation in the closure passed to `set` of (.+?)::(.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/better_scoped_tls/src/lib.rs","lineNumber":68,"sourceCode":"    #[cfg_attr(not(debug_assertions), inline(always))]\n    pub fn set<F, R>(&'static self, t: &T, f: F) -> R\n    where\n        F: FnOnce() -> R,\n    {\n        self.inner.set(t, f)\n    }\n\n    /// See [scoped_tls::ScopedKey] for actual documentation.\n    #[track_caller]\n    #[cfg_attr(not(debug_assertions), inline(always))]\n    pub fn with<F, R>(&'static self, f: F) -> R\n    where\n        F: FnOnce(&T) -> R,\n    {\n        #[cfg(debug_assertions)]\n        if !self.inner.is_set() {\n            // Override panic message\n            panic!(\n                \"You should perform this operation in the closure passed to `set` of {}::{}\",\n                self.module_path, self.name\n            )\n        }\n\n        self.inner.with(f)\n    }\n\n    /// See [scoped_tls::ScopedKey] for actual documentation.\n    #[cfg_attr(not(debug_assertions), inline(always))]\n    pub fn is_set(&'static self) -> bool {\n        self.inner.is_set()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/better_scoped_tls/src/lib.rs#L50-L86","documentation":"Runtime panic from better_scoped_tls (used throughout swc for COMMENTS, hygiene/marks, etc.). `ScopedKey::with` requires the thread-local slot to be set, which only happens inside the closure passed to `KEY.set(&value, ...)`. In debug builds the crate overrides the panic message to name the module and key; in release the underlying scoped_tls still panics with its own message.","triggerScenarios":"Calling `COMMENTS.with(|c| ...)` (or any swc TLS accessor) from code that runs outside the corresponding `.set(...)` closure — e.g. invoking a transform pass manually, calling from a freshly spawned thread, or from a drop handler after the set scope ended.","commonSituations":"Writing custom visitors/plugins that touch comments or hygiene data without entering through the swc compiler entry points; `set` is per-thread, so work moved to another thread loses the scope; debug builds surface it with this exact message.","solutions":["Wrap the entry point in the key's set closure: `COMMENTS.set(&comments, || { ... })`","If the code runs on another thread, call `.set(...)` again inside that thread before using `.with`","Restructure to pass Comments/Handler explicitly as parameters instead of relying on TLS"],"exampleFix":"// before\nfn my_pass() {\n    let c = COMMENTS.with(|c| c.clone()); // panics: not inside set\n}\n\n// after\nfn my_pass(comments: &Rc<RefCell<Comments>>) {\n    COMMENTS.set(comments, || {\n        let c = COMMENTS.with(|c| c.clone());\n        // ...\n    });\n}","handlingStrategy":"validation","validationCode":"if COMMENTS.is_set() {\n    COMMENTS.with(|c| {\n        // safe here\n    });\n} else {\n    // not inside a `set` scope: initialize it or return an error\n    return Err(anyhow::anyhow!(\"COMMENTS scope not entered\"));\n}","typeGuard":null,"tryCatchPattern":"let r = std::panic::catch_unwind(|| {\n    COMMENTS.with(|c| c.clone())\n});\nlet comments = match r {\n    Ok(c) => c,\n    Err(_) => return Err(anyhow::anyhow!(\"TLS key not set: called outside `set` closure\")),\n};","preventionTips":["Enter swc APIs only inside the corresponding `KEY.set(&value, closure)` scope","Remember `set` is per-thread: re-enter it inside any spawned thread","Prefer passing Comments/Handler explicitly over TLS access in library code","Test in debug builds — that is where the descriptive message fires"],"tags":["rust","scoped-tls","swc","thread-local","threading","debug-builds"],"backgroundTag":"scoped-tls-not-set","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"}