{"record":{"id":"f21300167e452ac6","repo":"libnyanpasu/clash-nyanpasu","slug":"url-event-received-before-prepare-was-called","errorCode":null,"errorMessage":"URL event received before prepare() was called","messagePattern":"URL event received before prepare\\(\\) was called","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/tauri-plugin-deep-link/src/macos.rs","lineNumber":88,"sourceCode":"            let mut cb = HANDLER.get().unwrap().lock().unwrap();\n            cb(s);\n        }\n    }\n);\n\nimpl Handler {\n    pub fn new() -> Retained<Self> {\n        let cls = Self::class();\n        unsafe { msg_send_id![msg_send_id![cls, alloc], init] }\n    }\n}\n\n#[cfg(debug_assertions)]\nfn secondary_handler(s: String) {\n    let addr = format!(\n        \"/tmp/{}-deep-link.sock\",\n        ID.get()\n            .expect(\"URL event received before prepare() was called\")\n    );\n    if let Ok(mut stream) = UnixStream::connect(addr) {\n        if let Err(io_err) = stream.write_all(s.as_bytes()) {\n            log::error!(\n                \"Error sending message to primary instance: {}\",\n                io_err.to_string()\n            );\n        };\n    }\n    std::process::exit(0);\n}\n\npub fn listen<F: FnMut(String) + Send + 'static>(handler: F) -> Result<()> {\n    #[cfg(debug_assertions)]\n    let addr = format!(\n        \"/tmp/{}-deep-link.sock\",\n        ID.get().expect(\"listen() called before prepare()\")\n    );","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/tauri-plugin-deep-link/src/macos.rs#L70-L106","documentation":"In debug builds on macOS, the secondary-instance handler reads the identifier from the ID OnceCell to build the /tmp/<id>-deep-link.sock path. If prepare() was never called, ID.get() returns None and this expect() panics. It enforces that prepare() precedes any URL event handling.","triggerScenarios":"A secondary instance receives a URL event (secondary_handler fires) before the app code called prepare(identifier); calling listen()/register() without prepare() first so no identifier was stored.","commonSituations":"Forgetting prepare() in a custom plugin setup; registering deep-link handling conditionally so prepare() is skipped on some code path while listen() still runs; macOS dev builds where single-instance handoff fires early.","solutions":["Call prepare(identifier) before register()/listen() in the app setup","Ensure every code path that can handle a URL runs prepare() first","If the identifier is dynamic, prepare() it before spawning any secondary-instance handler"],"exampleFix":"// before\nregister(\"myapp\");\n// after\nprepare(\"com.example.myapp\");\nregister(\"myapp\");","handlingStrategy":"validation","validationCode":"assert!(ID.get().is_some(), \"call prepare() before handling deep links\");","typeGuard":"fn is_prepared() -> bool { ID.get().is_some() }","tryCatchPattern":null,"preventionTips":["Always call prepare() before register()/listen()","Keep prepare() at the top of your deep-link init helper","Cover the startup path with a smoke test"],"tags":["rust","initialization","panic","deep-link","macos"],"backgroundTag":"invalid-state-transition","analyzedSha":"f7dbce2997c633e484f54788035e770b3ee99773","analyzedAt":"2026-09-08T01:24:59.197Z","contentChangedAt":"2026-09-08T01:24:59.197Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}