libnyanpasu/clash-nyanpasu · error

prepare() called more than once with different identifiers.

Error message

prepare() called more than once with different identifiers.

What it means

prepare() stores the deep-link plugin identifier in a OnceCell that can only be set once. If prepare() is called a second time with a different identifier than the first call, ID.set() returns Err and this expect() panics. The library uses this to guarantee a single, consistent per-app identifier for IPC socket paths.

Source

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

            if let Err(io_err) =
                stream.write_all(std::env::args().nth(1).unwrap_or_default().as_bytes())
            {
                log::error!(
                    "Error sending message to primary instance: {}",
                    io_err.to_string()
                );
            };
            std::process::exit(0);
        }
        Err(err) => {
            log::error!("Error creating socket listener: {}", err.to_string());
            if err.kind() == ErrorKind::ConnectionRefused {
                let _ = remove_file(&addr);
            }
        }
    };
    ID.set(identifier.to_string())
        .expect("prepare() called more than once with different identifiers.");
}

View on GitHub (pinned to f7dbce2997)

Solutions

  1. Call prepare() exactly once per process, early in the app entry point
  2. Use the same identifier string on every call (derive it from a single constant/config)
  3. If re-initialization is required, run it in a fresh process instead of calling prepare() again
  4. Guard with Once: use a wrapper that only forwards the first prepare() call

Example fix

// before
prepare("com.app.dev");
// ...
prepare("com.app.test"); // panics
// after
const IDENTIFIER: &str = "com.app.dev";
prepare(IDENTIFIER); // called once, from one place
Defensive patterns

Strategy: validation

Validate before calling

if ID.get().map(|id| id.as_str()) == Some(identifier) { return; } // skip duplicate prepare with same id
assert!(ID.get().is_none(), "prepare() already called");

Type guard

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

Prevention

When it happens

Trigger: Calling prepare(identifier) twice in one process with different identifier strings, e.g. during app re-initialization, hot-reload of the Tauri setup hook, or two test cases reusing one process with different bundle IDs.

Common situations: Dev hot-reload rebuilding the Tauri app state without restarting the process; test harnesses calling prepare() per test with a distinct identifier; accidentally invoking prepare() in both a plugin init hook and the app setup closure.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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