Hmbown/CodeWhale · error

local install path must not be empty

Error message

local install path must not be empty

What it means

PluginInstallSource::local handles the `path:<dir>` (and fallback) branch of source parsing. It trims the spec and rejects an empty remaining value, because a local plugin install must point at a concrete directory containing the plugin bundle.

Solutions

  1. Supply the directory after the prefix, e.g. `path:/home/me/plugins/myplugin`
  2. Fix the unset shell/config variable that emptied the path
  3. Validate the path is non-empty and exists before calling parse

Example fix

// before
source = "path:"
// after
source = "path:./plugins/my-plugin"
Defensive patterns

Strategy: validation

Validate before calling

fn local_path_spec_ok(spec: &str) -> bool { spec.strip_prefix("path:").map_or(true, |p| !p.trim().is_empty()) }

Try / catch

match PluginInstallSource::parse(spec) { Err(e) if e.to_string().contains("local install path must not be empty") => eprintln!("path: prefix requires a directory"), other => other?, }

Prevention

When it happens

Trigger: Passing `path:` with nothing after the prefix (e.g. `path:`, `path: `), or falling through to local() with an empty/whitespace string from a config field or unquoted shell variable.

Common situations: Config entry `source = "path:"` with the directory accidentally omitted; `path:$PLUGIN_DIR` where PLUGIN_DIR is empty; copy-paste dropping the actual path.

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 Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/161c07e37e0485bf. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/plugins/install/mod.rs:136

        {
            let source = InstallSource::parse(trimmed)?;
            return match source {
                InstallSource::GitHubRepo(_) | InstallSource::DirectUrl(_) => {
                    remote_bundle_path(&source)?;
                    Ok(Self::Remote(source))
                }
                InstallSource::Registry(_) => {
                    unreachable!("prefixed specs never parse as a registry name")
                }
            };
        }
        Self::local(trimmed)
    }

    fn local(spec: &str) -> Result<Self> {
        let trimmed = spec.trim();
        if trimmed.is_empty() {
            bail!("local install path must not be empty");
        }
        Ok(Self::LocalPath(PathBuf::from(trimmed)))
    }
}

/// Select one manifest-rooted bundle from a repository archive. The fragment
/// is local extraction metadata, never a path sent to or executed by a server.
fn remote_bundle_path(source: &InstallSource) -> Result<Option<String>> {
    let InstallSource::DirectUrl(raw) = source else {
        return Ok(None);
    };
    let url = reqwest::Url::parse(raw).context("invalid plugin archive URL")?;
    let Some(fragment) = url.fragment() else {
        return Ok(None);
    };
    let path = fragment
        .strip_prefix("path=")
        .context("plugin archive fragment must be #path=<bundle-directory>")?;

View on GitHub (pinned to 73e0f67d83)