libnyanpasu/clash-nyanpasu · error

Called register() before prepare()

Error message

Called register() before prepare()

What it means

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.

Source

Thrown at backend/tauri-plugin-deep-link/src/linux.rs:50

    target.push(&file_name);

    let mime_types = format!(
        "{};",
        schemes
            .iter()
            .map(|s| format!("x-scheme-handler/{}", s))
            .collect::<Vec<String>>()
            .join(";")
    );

    let mut file = File::create(&target)?;
    file.write_all(
        format!(
            include_str!("template.desktop"),
            name = ID
                .get()
                .expect("Called register() before prepare()")
                .split('.')
                .last()
                .unwrap(),
            exec = std::env::var("APPIMAGE").unwrap_or_else(|_| exe.display().to_string()),
            mime_types = mime_types
        )
        .as_bytes(),
    )?;

    // update-desktop-database [-q|--quiet] [-v|--verbose] [DIRECTORY...]
    target.pop();

    Command::new("update-desktop-database")
        .arg(&target)
        .status()?;

    for scheme in schemes {
        Command::new("xdg-mime")

View on GitHub (pinned to f7dbce2997)

Solutions

  1. Call prepare() (or set the ID via the plugin's prepare hook) before any register() call.
  2. Ensure the plugin is added through the Tauri builder so its setup/prepare hook runs at startup.
  3. Move manual register() calls into code that runs after plugin initialization completes.
  4. If you cannot reorder, gate register() behind a check that the ID is initialized and report a clear error instead.

Example fix

// before
register_all(); // calls register()
deep_link::prepare("com.example.app");

// after
deep_link::prepare("com.example.app");
register_all(); // register() now finds ID initialized
Defensive patterns

Strategy: validation

Validate before calling

// Call before register()
fn deep_link_ready() -> bool { /* ID OnceCell populated */ deep_link::is_prepared() }

Try / catch

match std::panic::catch_unwind(|| deep_link::register()) { Err(_) => eprintln!("call prepare() before register()"), ... }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08). Data as JSON: /api/errors/8fe1539de4d33d98. Report an issue: GitHub.