{"record":{"id":"43543f969c47705d","repo":"sinelaw/fresh","slug":"plugin-not-found","errorCode":null,"errorMessage":"Plugin '{}' not found","messagePattern":"Plugin '(.+?)' not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/fresh-plugin-runtime/src/thread.rs","lineNumber":1952,"sourceCode":"\n        // Unregister i18n strings\n        runtime\n            .borrow_mut()\n            .services\n            .unregister_plugin_strings(name);\n\n        // Remove all commands registered by this plugin\n        runtime\n            .borrow()\n            .services\n            .unregister_commands_by_plugin(name);\n\n        // Clean up plugin runtime state (context, event handlers, actions, callbacks)\n        runtime.borrow().cleanup_plugin(name);\n\n        Ok(())\n    } else {\n        Err(anyhow!(\"Plugin '{}' not found\", name))\n    }\n}\n\n/// Reload a plugin\nasync fn reload_plugin_internal(\n    runtime: Rc<RefCell<QuickJsBackend>>,\n    plugins: &mut HashMap<String, TsPluginInfo>,\n    name: &str,\n) -> Result<()> {\n    let path = plugins\n        .get(name)\n        .ok_or_else(|| anyhow!(\"Plugin '{}' not found\", name))?\n        .path\n        .clone();\n\n    unload_plugin_internal(Rc::clone(&runtime), plugins, name)?;\n    load_plugin_internal(runtime, plugins, &path).await?;\n","sourceCodeStart":1934,"sourceCodeEnd":1970,"githubUrl":"https://github.com/sinelaw/fresh/blob/67894ca5463dbd7a89bb31add4627c27d6b79d83/crates/fresh-plugin-runtime/src/thread.rs#L1934-L1970","documentation":"Raised by `unload_plugin_internal` when the given plugin name is not a key in the loaded-plugins `HashMap`. The runtime only unloads plugins it has previously loaded (removing their commands, i18n strings, and runtime state); requesting an unload for an unknown name returns this error instead of silently succeeding.","triggerScenarios":"Calling the unload API (directly or via a plugin-management command) with a `name` that was never loaded, already unloaded, or spelled differently than the registered name (the filename stem is the key).","commonSituations":"Double-unload after an earlier unload or failed load; unloading after a reload that renamed the plugin; name mismatch between the requested name and the file stem (e.g. `my_plugin` vs `my-plugin`); unloading a plugin whose initial load failed so it never entered the map.","solutions":["Check that the plugin is currently loaded (name exactly matches its file stem) before calling unload.","Treat 'not found' on unload as idempotent success if your flow may unload twice.","Verify the name used at load time matches; fix any normalization (case, hyphen/underscore) differences.","If the plugin failed to load earlier, clean up its state via the load error path instead of calling unload."],"exampleFix":"// before\nunload_plugin_internal(runtime, &mut plugins, \"My-Plugin\").await?;\n\n// after\nif plugins.contains_key(\"my-plugin\") {\n    unload_plugin_internal(runtime, &mut plugins, \"my-plugin\").await?;\n}","handlingStrategy":"try-catch","validationCode":"if !plugins.contains_key(name) {\n    eprintln!(\"plugin '{}' is not loaded; skipping unload\", name);\n    return Ok(());\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = unload_plugin_internal(Rc::clone(&runtime), &mut plugins, name).await {\n    if e.to_string().contains(\"not found\") {\n        tracing::debug!(\"unload ignored: plugin '{}' not loaded\", name); // treat as idempotent\n    } else {\n        return Err(e);\n    }\n}","preventionTips":["Track loaded plugin names in one place and only unload from that registry.","Make unload idempotent by checking membership first.","Use the exact file stem as the plugin name everywhere (no case/separator transforms).","Don't call unload after a failed load — the plugin was never registered."],"tags":["plugin-management","not-found","state"],"backgroundTag":"record-not-found","analyzedSha":"67894ca5463dbd7a89bb31add4627c27d6b79d83","analyzedAt":"2026-09-13T15:04:03.701Z","contentChangedAt":"2026-09-13T15:04:03.701Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}