{"record":{"id":"8fe1539de4d33d98","repo":"libnyanpasu/clash-nyanpasu","slug":"called-register-before-prepare","errorCode":null,"errorMessage":"Called register() before prepare()","messagePattern":"Called register\\(\\) before prepare\\(\\)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/tauri-plugin-deep-link/src/linux.rs","lineNumber":50,"sourceCode":"\n    target.push(&file_name);\n\n    let mime_types = format!(\n        \"{};\",\n        schemes\n            .iter()\n            .map(|s| format!(\"x-scheme-handler/{}\", s))\n            .collect::<Vec<String>>()\n            .join(\";\")\n    );\n\n    let mut file = File::create(&target)?;\n    file.write_all(\n        format!(\n            include_str!(\"template.desktop\"),\n            name = ID\n                .get()\n                .expect(\"Called register() before prepare()\")\n                .split('.')\n                .last()\n                .unwrap(),\n            exec = std::env::var(\"APPIMAGE\").unwrap_or_else(|_| exe.display().to_string()),\n            mime_types = mime_types\n        )\n        .as_bytes(),\n    )?;\n\n    // update-desktop-database [-q|--quiet] [-v|--verbose] [DIRECTORY...]\n    target.pop();\n\n    Command::new(\"update-desktop-database\")\n        .arg(&target)\n        .status()?;\n\n    for scheme in schemes {\n        Command::new(\"xdg-mime\")","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/tauri-plugin-deep-link/src/linux.rs#L32-L68","documentation":"On Linux, the deep-link plugin's register() writes a .desktop template that reads the app ID from a OnceCell (ID) populated by prepare(). Calling register() before prepare() leaves ID empty, and ID.get().expect(...) panics. This enforces the plugin's required initialization order: prepare() must run first.","triggerScenarios":"Invoking the plugin's register() (desktop-file registration) before calling prepare() in the same process, e.g. registering deep links during early setup before the plugin's prepare hook ran.","commonSituations":"Custom startup code that registers deep-link handlers manually before the Tauri plugin builder's prepare step; refactors that move plugin setup out of the standard builder chain; AppImage packaging scripts calling register too early.","solutions":["Call prepare() (or set the ID via the plugin's prepare hook) before any register() call.","Ensure the plugin is added through the Tauri builder so its setup/prepare hook runs at startup.","Move manual register() calls into code that runs after plugin initialization completes.","If you cannot reorder, gate register() behind a check that the ID is initialized and report a clear error instead."],"exampleFix":"// before\nregister_all(); // calls register()\ndeep_link::prepare(\"com.example.app\");\n\n// after\ndeep_link::prepare(\"com.example.app\");\nregister_all(); // register() now finds ID initialized","handlingStrategy":"validation","validationCode":"// Call before register()\nfn deep_link_ready() -> bool { /* ID OnceCell populated */ deep_link::is_prepared() }","typeGuard":null,"tryCatchPattern":"match std::panic::catch_unwind(|| deep_link::register()) { Err(_) => eprintln!(\"call prepare() before register()\"), ... }","preventionTips":["Always run prepare() before register().","Register the plugin through the standard Tauri builder so prepare runs automatically.","Keep manual deep-link setup in the app setup callback, after plugin init.","Add a startup assertion that prepare() completed."],"tags":["panic","initialization-order","deep-link","linux"],"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"}