astrid-runtime/astrid · error

Invalid GitHub URL format. Expected github.com/org/repo or…

Error message

Invalid GitHub URL format. Expected github.com/org/repo or @org/repo

What it means

Raised in install_from_github when extract_github_org_repo cannot derive an (org, repo) pair from the provided URL. The installer accepts github.com/org/repo style URLs or @org/repo shorthand; anything else fails before any network request.

Solutions

  1. Use the @org/repo shorthand form
  2. Or use github.com/org/repo without scheme or .git suffix
  3. Strip https://, git@, trailing .git, and extra path segments from the URL

Example fix

// before
--from git@github.com:org/repo.git
// after
--from @org/repo
Defensive patterns

Strategy: validation

Validate before calling

fn is_installable_github_ref(s: &str) -> bool {
    s.starts_with("@") && s[1..].split('/').count() == 2
        || s.starts_with("github.com/") && s["github.com/".len()..].split('/').count() == 2
}

Type guard

fn parse_org_repo(s: &str) -> Option<(String, String)> {
    let rest = s.strip_prefix("@").or_else(|| s.strip_prefix("github.com/"))?;
    let mut it = rest.split('/');
    Some((it.next()?.to_string(), it.next()?.to_string()))
}

Try / catch

match install_from_github(url).await { Err(e) if e.to_string().contains("Invalid GitHub URL format") => { eprintln!("use @org/repo or github.com/org/repo"); std::process::exit(2) }, other => other }

Prevention

When it happens

Trigger: Passing a bare repo name ('myrepo'), a full https:// prefix the extractor doesn't handle, a git SSH URL (git@github.com:org/repo), or a URL with extra path segments the parser rejects.

Common situations: Copy-pasting the clone URL (https://github.com/org/repo.git or SSH form) instead of the supported formats, or passing just the repo slug from memory.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/5891f97714666cda. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-cli/src/commands/capsule/install.rs:318

/// Install from a GitHub source, returning the concrete ref that was
/// actually resolved and fetched (`Some` on the release-asset path). The
/// clone-and-build fallback returns `None` — there is no single release
/// tag it resolved (it builds from whatever `--depth 1` HEAD it cloned).
async fn install_from_github(
    url: &str,
    name_hint: Option<&str>,
    version: Option<&str>,
    tag: Option<&str>,
    context: InstallContext<'_>,
) -> anyhow::Result<(Vec<InstalledCapsuleOutcome>, Option<String>)> {
    // Authenticated when a token is present so release resolution isn't
    // throttled at the anonymous 60/hr limit mid-distro (see
    // `github_api_client`).
    let client = github_api_client()?;

    let (org, repo) = extract_github_org_repo(url).ok_or_else(|| {
        anyhow::anyhow!("Invalid GitHub URL format. Expected github.com/org/repo or @org/repo")
    })?;

    // Whether the caller pinned a concrete release. A pin is a hard
    // contract: if it cannot be honored we fail loudly rather than build
    // HEAD, which would install something other than what was pinned and
    // break the reproducibility the pin exists to guarantee.
    let pinned = version.is_some() || tag.is_some();

    // Priority 1: download packed `.capsule` archive(s) from the release
    // resolved by version/tag (or latest when unpinned). Each archive
    // contains everything an install needs (WASM, manifest, bundled WIT
    // definitions). The ref resolved here is the *actually resolved* tag —
    // the single source of truth threaded into the lock; we never silently
    // fall back to `releases/latest` when a version/tag is pinned.
    match resolve_github_ref(&client, org, repo, version, tag).await {
        Ok(resolved_ref) => {
            // Fetch the resolved release's assets. Build the URL via
            // `release_tag_url` so a tag containing `/` is percent-encoded as

View on GitHub (pinned to affd8760f4)