{"record":{"id":"f652d5154fa564d8","repo":"neon-bindings/neon","slug":"attempt-to-reinitialize-local-during-initialization","errorCode":null,"errorMessage":"attempt to reinitialize Local during initialization","messagePattern":"attempt to reinitialize Local during initialization","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/neon/src/lifecycle.rs","lineNumber":100,"sourceCode":"    /// Intermediate \"dirty\" state representing the middle of a `get_or_try_init` transaction.\n    Trying,\n    /// Fully initialized state.\n    Init(LocalCellValue),\n}\n\nimpl LocalCell {\n    /// Establish the initial state at the beginning of the initialization protocol.\n    /// This method ensures that re-entrant initialization always panics (i.e. when\n    /// an existing `get_or_try_init` is in progress).\n    fn pre_init<F>(&mut self, f: F)\n    where\n        F: FnOnce() -> LocalCell,\n    {\n        match self {\n            LocalCell::Uninit => {\n                *self = f();\n            }\n            LocalCell::Trying => panic!(\"attempt to reinitialize Local during initialization\"),\n            LocalCell::Init(_) => {}\n        }\n    }\n\n    pub(crate) fn get<'cx, 'a, C>(cx: &'a mut C, id: usize) -> Option<&'a mut LocalCellValue>\n    where\n        C: Context<'cx>,\n    {\n        let cell = InstanceData::locals(cx).get(id);\n        match cell {\n            LocalCell::Init(ref mut b) => Some(b),\n            _ => None,\n        }\n    }\n\n    pub(crate) fn get_or_init<'cx, 'a, C, F>(\n        cx: &'a mut C,\n        id: usize,","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/neon-bindings/neon/blob/38960e4381d9ad13b551cdf2d261f609167c9bc2/crates/neon/src/lifecycle.rs#L82-L118","documentation":"`LocalCell::pre_init` initializes thread-local Neon state exactly once, using an `Uninit/Trying/Init` state machine. Panicking with this message means `pre_init` (or the initializing closure) was re-entered while the cell was still in the `Trying` state — i.e. the initialization function itself tried to read the same thread-local value, causing illegal recursive initialization.","triggerScenarios":"The closure passed to `pre_init` (or anything it calls, directly or transitively) accesses the same `LocalCell` thread-local before initialization completes — e.g. instance-data setup code that calls back into Neon APIs which read instance state; re-entrant module initialization on the same thread.","commonSituations":"Custom `InstanceData`/singleton setup that calls Neon context APIs during initialization; logging or panic hooks that touch Neon thread-locals during init; cyclic initialization between two lazily-initialized globals.","solutions":["Remove any access to Neon instance/thread-local state from inside the `pre_init` initializer closure; compute plain values first, store them, and only use Neon APIs afterwards.","Break initialization cycles between globals by initializing dependencies explicitly before entering Neon init.","Avoid calling exported Neon functions from init-time hooks (loggers, signal handlers, atexit).","If triggered by a Neon upgrade, check the changelog for pre_init semantics and update custom `Instance`/instance-data code to the current API."],"exampleFix":"// before\nINSTANCE.pre_init(|cell| {\n    let cx = current_cx(); // reads the same LocalCell -> re-entrant init\n    cell.store(build_data(cx))\n});\n\n// after\nlet data = build_data_plain(); // no Neon thread-local access\nINSTANCE.pre_init(|cell| cell.store(data));","handlingStrategy":"validation","validationCode":"// audit init-time code: nothing inside pre_init closures may touch Neon APIs\nfn assert_no_neon_in_init<F: FnOnce()>(f: F) { f(); } // review-only pattern","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep pre_init closures free of Neon context/thread-local access","Initialize dependencies (loggers, globals) before Neon module init","Don't call exported Neon functions from panic hooks or signal handlers","After Neon upgrades, re-check custom instance-data initialization against the new API"],"tags":["rust","neon","initialization","thread-local"],"backgroundTag":"internal-invariant-violation","analyzedSha":"38960e4381d9ad13b551cdf2d261f609167c9bc2","analyzedAt":"2026-09-13T09:05:33.640Z","contentChangedAt":"2026-09-13T09:05:33.640Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}