Hmbown/CodeWhale · error

install source must not be empty

Error message

install source must not be empty

What it means

InstallSource::parse rejects an empty or whitespace-only skill install spec before any network or filesystem work. Every non-empty spec routes into the github:/https://registry classification, so this error purely means nothing was passed to install.

Source

Thrown at crates/tui/src/skills/install.rs:118

    GitHubRepo(String),
    /// Raw `http(s)://…` tarball URL. Used as-is.
    DirectUrl(String),
    /// Curated registry lookup key. Looked up via the configured `registry_url`.
    Registry(String),
}

impl InstallSource {
    /// Parse a user-supplied spec. Empty / whitespace-only input is rejected.
    ///
    /// * `github:owner/repo` → [`InstallSource::GitHubRepo`]
    /// * `https://github.com/owner/repo[.git]` (no path past the repo) →
    ///   [`InstallSource::GitHubRepo`]
    /// * any other `http://` or `https://` prefix → [`InstallSource::DirectUrl`]
    /// * anything else → [`InstallSource::Registry`]
    pub fn parse(spec: &str) -> Result<Self> {
        let trimmed = spec.trim();
        if trimmed.is_empty() {
            bail!("install source must not be empty");
        }
        if let Some(rest) = trimmed.strip_prefix("github:") {
            let rest = rest.trim();
            // Reject obviously bogus values up front. We intentionally accept
            // case-insensitive owner/repo so `github:Hmbown/Foo` works.
            let (owner, repo) = rest.split_once('/').with_context(|| {
                format!("github source must be 'github:owner/repo' (got {spec})")
            })?;
            let owner = owner.trim();
            let repo = repo.trim().trim_end_matches('/');
            if owner.is_empty() || repo.is_empty() {
                bail!("github source must be 'github:owner/repo' (got {spec})");
            }
            if owner.contains('/') || repo.contains('/') {
                bail!("github source must be 'github:owner/repo' (got {spec})");
            }
            return Ok(Self::GitHubRepo(format!("{owner}/{repo}")));
        }

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Pass a real spec: 'github:owner/repo', an https URL, or a registry name.
  2. If a wrapper builds the spec from variables, assert it is non-empty before invoking install.
  3. Quote arguments so unbound variables do not collapse to empty strings.
  4. Treat as a pure input error: nothing was fetched, no cleanup is needed.

Example fix

# before
/skill install ""

# after
/skill install github:owner/repo
Defensive patterns

Strategy: validation

Validate before calling

let spec = spec.trim();
if spec.is_empty() {
    eprintln!("skill spec is required: github:owner/repo, https URL, or registry name");
    return;
}

Prevention

When it happens

Trigger: Invoking the skill install flow with an empty argument: '/skill install' with no spec, a spec of only spaces, or a wrapper passing an unset environment variable as the spec.

Common situations: Argument-parsing bugs in wrappers, empty-string defaults ('${SKILL_SPEC:-}'), copy-paste that lost the spec, and UI flows submitting before input.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/0ea02840a46a743c. Report an issue: GitHub.