tauri-apps/tauri · error

valid plugin

Error message

valid plugin

What it means

Plugin Builder::build() calls try_build(), which currently fails only when the plugin name is reserved: RESERVED_PLUGIN_NAMES = ["core", "tauri"] (crates/tauri/src/plugin.rs:191). Those names belong to Tauri's own namespace, so building a plugin with one panics with 'valid plugin'.

Source

Thrown at crates/tauri/src/plugin.rs:755

      setup: self.setup,
      js_init_script: self.js_init_script,
      on_navigation: self.on_navigation,
      on_page_load: self.on_page_load,
      on_window_ready: self.on_window_ready,
      on_webview_ready: self.on_webview_ready,
      on_event: self.on_event,
      on_drop: self.on_drop,
      uri_scheme_protocols: self.uri_scheme_protocols,
    })
  }

  /// Builds the [`TauriPlugin`].
  ///
  /// # Panics
  ///
  /// If the builder returns an error during [`Self::try_build`], then this method will panic.
  pub fn build(self) -> TauriPlugin<R, C> {
    self.try_build().expect("valid plugin")
  }
}

/// Plugin struct that is returned by the [`Builder`]. Should only be constructed through the builder.
pub struct TauriPlugin<R: Runtime, C: DeserializeOwned = ()> {
  name: &'static str,
  app: Option<AppHandle<R>>,
  invoke_handler: Box<InvokeHandler<R>>,
  setup: Option<Box<SetupHook<R, C>>>,
  js_init_script: Option<InitializationScript>,
  on_navigation: Box<OnNavigation<R>>,
  on_page_load: Box<OnPageLoad<R>>,
  on_window_ready: Box<OnWindowReady<R>>,
  on_webview_ready: Box<OnWebviewReady<R>>,
  on_event: Box<OnEvent<R>>,
  on_drop: Option<Box<OnDrop<R>>>,
  uri_scheme_protocols: HashMap<String, Arc<UriSchemeProtocol<R>>>,
}

View on GitHub (pinned to 52e4b6e71d)

Solutions

  1. Rename the plugin to anything other than 'core' or 'tauri'.
  2. For graceful handling, call try_build() and match BuilderError::ReservedName instead of build().

Example fix

// before
let plugin = tauri::plugin::Builder::<R>::new("core").build();

// after
let plugin = tauri::plugin::Builder::<R>::new("app-core").build();
// or: match builder.try_build() { Ok(p) => p, Err(e) => /* handle */ }
Defensive patterns

Strategy: try-catch

Validate before calling

assert!(!matches!(name, "core" | "tauri"), "plugin name '{name}' is reserved");

Type guard

fn is_valid_plugin_name(name: &str) -> bool {
    !matches!(name, "core" | "tauri")
}

Try / catch

match tauri::plugin::Builder::<R>::new(name).try_build() {
    Ok(plugin) => plugin,
    Err(tauri::plugin::BuilderError::ReservedName(n)) => {
        // rename or surface a configuration error
        return Err(format!("plugin name '{n}' is reserved"));
    }
    Err(e) => return Err(e.to_string()),
}

Prevention

When it happens

Trigger: tauri::plugin::Builder::new("core").build() or Builder::new("tauri").build() — any custom plugin constructed with one of those two names.

Common situations: Writing a custom plugin and naming it 'core' or 'tauri' (e.g. an internal core module exposed as a plugin).

Related errors


AI-assisted analysis of tauri-apps/tauri@52e4b6e71d (2026-08-20). Data as JSON: /api/errors/586702ff5c498a27. Report an issue: GitHub.