zellij-org/zellij · error

Plugin is not stored in memory

Error message

Plugin is not stored in memory

What it means

Thrown by PluginLoader::load_module_from_memory when a plugin reload expects the already-compiled wasm Module to be parked in the internal plugin_cache keyed by plugin path, but the cache has no entry. The cache is consumed with a one-shot .remove(), so the entry is only present between the first load and the first reload. A miss means the reload path was taken for a plugin that was never cached (or was already reloaded once).

Source

Thrown at zellij-server/src/plugins/plugin_loader.rs:165

        self.loading_indication.override_previous_error();
        let wasm_bytes = self.plugin_config.resolve_wasm_bytes(&self.plugin_dir)?;
        let timer = std::time::Instant::now();
        let module = Module::new(&self.engine, &wasm_bytes)?;
        log::info!(
            "Loaded plugin '{}' in {:?}",
            self.plugin_config.path.display(),
            timer.elapsed()
        );
        Ok(module)
    }
    fn load_module_from_memory(&mut self) -> Result<Module> {
        let module = self
            .plugin_cache
            .lock()
            .unwrap()
            .remove(&self.plugin_config.path) // TODO: do we still bring it back later?
            // maybe we can forgo this dance?
            .ok_or(anyhow!("Plugin is not stored in memory"))?;
        Ok(module)
    }
    fn load_plugin_instance(
        &mut self,
        mut store: Store<PluginEnv>,
        instance: &Instance,
    ) -> Result<()> {
        let err_context = || format!("failed to load plugin from instance {instance:#?}");
        let main_user_instance = instance.clone();
        let start_function = instance
            .get_typed_func::<(), ()>(&mut store, "_start")
            .with_context(err_context)?;
        let load_function = instance
            .get_typed_func::<(), ()>(&mut store, "load")
            .with_context(err_context)?;
        let mut workers = HashMap::new();
        for function_name in instance
            .exports(&mut store)

View on GitHub (pinned to 98a0837077)

Solutions

  1. Ensure the plugin's first load goes through the code path that inserts the module into plugin_cache (same RunPluginOrAlias path/normalization on both loads) so the reload finds it
  2. Avoid triggering reload of the same plugin twice; after the first reload the cache entry is gone by design (see the TODO at zellij-server/src/plugins/plugin_loader.rs:167)
  3. If you control this code, fall back to load_module_from_disk when load_module_from_memory returns None instead of erroring
  4. Check for concurrent loads of the identical plugin path (e.g. same plugin in tiled and floating panes) and serialize/reuse them

Example fix

// before
let module = self.load_module_from_memory()?;

// after
let module = match self.load_module_from_memory() {
    Ok(module) => module,
    Err(_) => self.load_module_from_disk()?, // recompile instead of failing
};
Defensive patterns

Strategy: fallback

Validate before calling

// before reloading, ensure a cached module exists for this exact path
let cached = plugin_cache.lock().unwrap().contains_key(&plugin_config.path);
if !cached { plugin_loader.load_module_from_disk()?; } // repopulates path for reload

Prevention

When it happens

Trigger: Calling start_or_reload on a plugin whose initial load went through load_module_from_disk (never inserted into plugin_cache), reloading the same plugin path twice (the first reload removed the entry), or a cache eviction/race between concurrent loads of the same path.

Common situations: Plugin development with `zellij --layout` hot-reload workflows; two panes loading the same plugin URL causing one to drain the cache; version change altering the cache-insertion path so file-loaded plugins skip caching.

Related errors


AI-assisted analysis of zellij-org/zellij@98a0837077 (2026-08-16). Data as JSON: /api/errors/90e2028719358148. Report an issue: GitHub.