tonhowtf/omniget · error

external_data_cache: namespace must not be empty

Error message

external_data_cache: namespace must not be empty

What it means

`external_data_cache` requires a non-empty `namespace` to build a per-namespace cache subdirectory; an empty namespace would map all plugins' cache files into one directory. It bails via anyhow before touching the filesystem.

Solutions

  1. Provide a meaningful namespace constant when calling the cache API
  2. Read namespace from plugin config and validate non-empty before use
  3. Reject plugins whose cache calls use empty namespaces at registration

Example fix

// before
host.external_data_cache(id, "")?;
// after
let ns = config.namespace.as_deref().unwrap_or("default");
ensure!(!ns.is_empty(), "namespace required");
host.external_data_cache(id, ns)?;
Defensive patterns

Strategy: validation

Validate before calling

if namespace.is_empty() { return Err(anyhow!("namespace required before cache access")); }

Type guard

fn valid_namespace(ns: &str) -> bool { !ns.is_empty() && !ns.contains(['/', '\\', ':', '\0']) }

Try / catch

let cache = host.external_data_cache(id, ns)
    .with_context(|| format!("cache namespace {ns:?}"))?;

Prevention

When it happens

Trigger: Calling external_data_cache with `namespace: ""`, e.g. a hardcoded empty string, a config key that resolved to empty, or an optional namespace field left unset.

Common situations: Plugin author forgets to set the namespace constant; data read from a JSON/IPC message has an empty namespace field; refactoring removed the default namespace value.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/3b79947dceee9172. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/src/plugin_host.rs:118

        if managed_path.exists() {
            return Some(managed_path);
        }

        which::which(&bin_name).ok()
    }

    fn default_output_dir(&self) -> PathBuf {
        dirs::download_dir()
            .or_else(dirs::home_dir)
            .unwrap_or_else(|| PathBuf::from("."))
    }

    fn external_data_cache(&self, plugin_id: &str, namespace: &str) -> anyhow::Result<PathBuf> {
        if plugin_id.is_empty() {
            anyhow::bail!("external_data_cache: plugin_id must not be empty");
        }
        if namespace.is_empty() {
            anyhow::bail!("external_data_cache: namespace must not be empty");
        }
        if plugin_id.contains(['/', '\\', ':', '\0']) || namespace.contains(['/', '\\', ':', '\0'])
        {
            anyhow::bail!(
                "external_data_cache: plugin_id/namespace must not contain path separators or null bytes"
            );
        }

        // portable installs keep every file next to the app, so the cache
        // lives under the app data dir instead of the OS cache dir
        let base = if std::env::var("OMNIGET_PORTABLE").is_ok() {
            omniget_core::core::paths::app_data_dir()
                .ok_or_else(|| anyhow::anyhow!("external_data_cache: app data dir unavailable"))?
                .join("cache")
        } else {
            dirs::cache_dir()
                .ok_or_else(|| {
                    anyhow::anyhow!(

View on GitHub (pinned to 8600b91f42)