{"record":{"id":"cf8ba4655bb4a1d9","repo":"libnyanpasu/clash-nyanpasu","slug":"register-called-before-prepare","errorCode":null,"errorMessage":"register() called before prepare()","messagePattern":"register\\(\\) called before prepare\\(\\)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/tauri-plugin-deep-link/src/windows.rs","lineNumber":45,"sourceCode":"\npub fn register<F: FnMut(String) + Send + 'static>(schemes: &[&str], handler: F) -> Result<()> {\n    listen(handler)?;\n\n    for scheme in schemes {\n        let hkcu = RegKey::predef(HKEY_CURRENT_USER);\n        let base = Path::new(\"Software\").join(\"Classes\").join(scheme);\n\n        let exe = tauri_utils::platform::current_exe()?\n            .display()\n            .to_string()\n            .replace(\"\\\\\\\\?\\\\\", \"\");\n\n        let (key, _) = hkcu.create_subkey(&base)?;\n        key.set_value(\n            \"\",\n            &format!(\n                \"URL:{}\",\n                ID.get().expect(\"register() called before prepare()\")\n            ),\n        )?;\n        key.set_value(\"URL Protocol\", &\"\")?;\n\n        let (icon, _) = hkcu.create_subkey(base.join(\"DefaultIcon\"))?;\n        icon.set_value(\"\", &format!(\"\\\"{}\\\",0\", exe))?;\n\n        let (cmd, _) = hkcu.create_subkey(base.join(\"shell\").join(\"open\").join(\"command\"))?;\n\n        cmd.set_value(\"\", &format!(\"\\\"{}\\\" \\\"%1\\\"\", exe))?;\n    }\n\n    Ok(())\n}\n\npub fn unregister(schemes: &[&str]) -> Result<()> {\n    for scheme in schemes {\n        let hkcu = RegKey::predef(HKEY_CURRENT_USER);","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/tauri-plugin-deep-link/src/windows.rs#L27-L63","documentation":"register() on Windows writes a registry key whose display value is 'URL:<identifier>', reading the identifier from the ID OnceCell. If prepare() was not called first, ID.get() is None and this expect() panics. prepare() must precede register().","triggerScenarios":"Calling register() before prepare(); registering the URL scheme during installer/init code that runs before the plugin's prepare(); conditional setup that skips prepare().","commonSituations":"Custom scheme registration invoked early in app bootstrap; refactors that moved register() before prepare(); tests calling register() standalone.","solutions":["Call prepare(identifier) before register()","Move both calls into one setup function so ordering is enforced","In tests, prepare() in a common setup step before register()"],"exampleFix":"// before\nregister(\"myapp\");\n// after\nprepare(\"com.example.myapp\");\nregister(\"myapp\");","handlingStrategy":"validation","validationCode":"assert!(ID.get().is_some(), \"call prepare() before register()\");","typeGuard":"fn is_prepared() -> bool { ID.get().is_some() }","tryCatchPattern":null,"preventionTips":["Call prepare() before any registry/scheme registration","Group prepare()+register() in one init function","Keep registration out of installer-time code that skips prepare()"],"tags":["rust","windows","registry","deep-link","initialization"],"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"}