libnyanpasu/clash-nyanpasu · error

register() called before prepare()

Error message

register() called before prepare()

What it means

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().

Source

Thrown at backend/tauri-plugin-deep-link/src/windows.rs:45

pub fn register<F: FnMut(String) + Send + 'static>(schemes: &[&str], handler: F) -> Result<()> {
    listen(handler)?;

    for scheme in schemes {
        let hkcu = RegKey::predef(HKEY_CURRENT_USER);
        let base = Path::new("Software").join("Classes").join(scheme);

        let exe = tauri_utils::platform::current_exe()?
            .display()
            .to_string()
            .replace("\\\\?\\", "");

        let (key, _) = hkcu.create_subkey(&base)?;
        key.set_value(
            "",
            &format!(
                "URL:{}",
                ID.get().expect("register() called before prepare()")
            ),
        )?;
        key.set_value("URL Protocol", &"")?;

        let (icon, _) = hkcu.create_subkey(base.join("DefaultIcon"))?;
        icon.set_value("", &format!("\"{}\",0", exe))?;

        let (cmd, _) = hkcu.create_subkey(base.join("shell").join("open").join("command"))?;

        cmd.set_value("", &format!("\"{}\" \"%1\"", exe))?;
    }

    Ok(())
}

pub fn unregister(schemes: &[&str]) -> Result<()> {
    for scheme in schemes {
        let hkcu = RegKey::predef(HKEY_CURRENT_USER);

View on GitHub (pinned to f7dbce2997)

Solutions

  1. Call prepare(identifier) before register()
  2. Move both calls into one setup function so ordering is enforced
  3. In tests, prepare() in a common setup step before register()

Example fix

// before
register("myapp");
// after
prepare("com.example.myapp");
register("myapp");
Defensive patterns

Strategy: validation

Validate before calling

assert!(ID.get().is_some(), "call prepare() before register()");

Type guard

fn is_prepared() -> bool { ID.get().is_some() }

Prevention

When it happens

Trigger: Calling register() before prepare(); registering the URL scheme during installer/init code that runs before the plugin's prepare(); conditional setup that skips prepare().

Common situations: Custom scheme registration invoked early in app bootstrap; refactors that moved register() before prepare(); tests calling register() standalone.

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/cf8ba4655bb4a1d9. Report an issue: GitHub.