{"record":{"id":"5d42c4b9cad1b7fa","repo":"zellij-org/zellij","slug":"failed-to-load-plugin-from-disk","errorCode":null,"errorMessage":"failed to load plugin from disk","messagePattern":"failed to load plugin from disk","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"zellij-utils/src/input/plugins.rs","lineNumber":129,"sourceCode":"            plugin_dir.join(&self.path).with_extension(\"wasm\"),\n        ];\n        #[cfg(not(target_family = \"wasm\"))]\n        paths.push(\n            crate::home::system_data_dir()\n                .join(\"plugins\")\n                .join(&self.path)\n                .with_extension(\"wasm\"),\n        );\n        // Throw out dupes, because it's confusing to read that zellij checked the same plugin\n        // location multiple times. Do NOT sort the vector here, because it will break the lookup!\n        paths.dedup();\n\n        // This looks weird and usually we would handle errors like this differently, but in this\n        // case it's helpful for users and developers alike. This way we preserve all the lookup\n        // errors and can report all of them back. We must initialize `last_err` with something,\n        // and since the user will only get to see it when loading a plugin failed, we may as well\n        // spell it out right here.\n        let mut last_err: Result<Vec<u8>> = Err(anyhow!(\"failed to load plugin from disk\"));\n        for path in paths {\n            // Check if the plugin path matches an entry in the asset map. If so, load it directly\n            // from memory, don't bother with the disk.\n            #[cfg(not(target_family = \"wasm\"))]\n            if !cfg!(feature = \"disable_automatic_asset_installation\") && self.is_builtin() {\n                let asset_path = PathBuf::from(\"plugins\").join(&path);\n                if let Some(bytes) = ASSET_MAP.get(&asset_path) {\n                    log::debug!(\"Loaded plugin '{}' from internal assets\", path.display());\n\n                    if plugin_dir.join(&path).with_extension(\"wasm\").exists() {\n                        log::info!(\n                            \"Plugin '{}' exists in the 'PLUGIN DIR' at '{}' but is being ignored\",\n                            path.display(),\n                            plugin_dir.display()\n                        );\n                    }\n\n                    return Ok(bytes.to_vec());","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/zellij-org/zellij/blob/98a0837077492d53dd252ab30bc3e43e41e504f4/zellij-utils/src/input/plugins.rs#L111-L147","documentation":"Initial value of last_err in PluginTag/RunPluginLocation::resolve_wasm_bytes (zellij-utils/input/plugins.rs). Zellij tries a chain of candidate paths for every configured plugin — the raw path, path + '.wasm', <plugin_dir>/<path>.wasm, and <system_data_dir>/plugins/<path>.wasm — plus the built-in ASSET_MAP for 'zellij:'-prefixed plugins. If no candidate yields bytes, this seed error is returned with every attempted path attached as anyhow context, so the final message enumerates the whole failed lookup chain.","triggerScenarios":"A config/layout names a plugin whose wasm exists in none of the lookup locations: typo'd or nonexistent plugin name, plugin file not installed into the plugin directory, unreadable file (permissions), or a zellij: builtin referenced in a build compiled with disable_automatic_asset_installation but without the asset installed to disk.","commonSituations":"Fresh machine where third-party plugins were never downloaded; custom plugin path relative vs absolute confusion (relative resolves against plugin dir, not cwd); wrong XDG_DATA_HOME/DATA_DIR so the plugin dir differs from expectation; permission-denied on the .wasm; typo like 'tabbar' instead of 'tab-bar'.","solutions":["Verify the plugin name/path spelling in the layout/config against the actual file name","Install the wasm into the plugin dir (usually ~/.local/share/zellij/plugins/<name>.wasm) or reference it by absolute path","For builtins use the 'zellij:' prefix (e.g. zellij:tab-bar) so the asset map resolves it","Run `zellij setup --check` to confirm the resolved data/plugin directories, and check permissions on the file","Reinstall zellij if built with disable_automatic_asset_installation and builtin plugins are missing from disk"],"exampleFix":"// before (layout.kdl)\nlayout {\n    pane plugin=\"my-status\" // not found anywhere in the lookup chain\n}\n\n// after\nlayout {\n    pane plugin=\"file:/home/bob/.local/share/zellij/plugins/my-status.wasm\"\n}","handlingStrategy":"validation","validationCode":"// before starting a session with a layout referencing a plugin\nlet candidates = [\n    plugin_dir.join(&name).with_extension(\"wasm\"),\n    std::path::PathBuf::from(&name),\n];\nlet builtin = name.starts_with(\"zellij:\");\nif !builtin && !candidates.iter().any(|p| p.is_file()) {\n    anyhow::bail!(\"plugin '{name}' not found in any lookup path; install it or use an absolute path\");\n}","typeGuard":"fn plugin_resolves(name: &str, plugin_dir: &std::path::Path) -> bool {\n    name.starts_with(\"zellij:\")\n        || std::path::Path::new(name).is_file()\n        || plugin_dir.join(name).with_extension(\"wasm\").is_file()\n        || crate::home::system_data_dir().join(\"plugins\").join(name).with_extension(\"wasm\").is_file()\n}","tryCatchPattern":"match run_plugin_location.resolve_wasm_bytes(&plugin_dir) {\n    Ok(bytes) => spawn_plugin(bytes)?,\n    Err(e) if e.to_string().contains(\"failed to load plugin from disk\") => {\n        // error chain lists every attempted path — surface it, skip this plugin, keep session alive\n        log::error!(\"skipping plugin, all lookups failed: {e:#}\");\n    },\n    Err(e) => return Err(e),\n}","preventionTips":["Use absolute file: paths or the zellij: builtin prefix to make resolution deterministic","Install third-party wams into the plugin dir reported by `zellij setup --check`","Validate layouts in CI by launching a throwaway session before shipping config","Remember the chain: name, name.wasm, <plugin_dir>/name.wasm, <data_dir>/plugins/name.wasm"],"tags":["plugin","wasm","filesystem","config","layout"],"backgroundTag":null,"analyzedSha":"98a0837077492d53dd252ab30bc3e43e41e504f4","analyzedAt":"2026-08-16T13:02:01.396Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}