jdx/mise · error

unsupported GitHub operation

Error message

unsupported GitHub operation

What it means

`authorize` only recognizes three relayed URL shapes: API repo calls (`/api/repos/{owner}/{repo}/...`), git smart-HTTP paths (`/git/{owner}/{repo}/...`), and web download paths (`/web/{owner}/{repo}/...`). Any path that does not match one of these prefixes fails with this error before any scope or method check runs.

Source

Thrown at src/github_relay.rs:202

        if decoded.is_empty()
            || matches!(decoded.as_ref(), "." | "..")
            || decoded.contains(['/', '\\', '%'])
            || decoded.chars().any(char::is_control)
        {
            bail!("invalid relay path");
        }
    }
    Ok(())
}

#[cfg(any(unix, test))]
fn authorize(scope: &Scope, method: &str, path: &str, query: Option<&str>) -> Result<Target> {
    validate_path(path)?;
    let p: Vec<_> = path.split('/').collect();
    let (owner, repo) = match p.as_slice() {
        ["api", "repos", owner, repo, ..] => (*owner, *repo),
        ["git" | "web", owner, repo, ..] => (*owner, repo.strip_suffix(".git").unwrap_or(repo)),
        _ => bail!("unsupported GitHub operation"),
    };
    let name = repository(&format!("{owner}/{repo}"))?;
    if !scope.permits(&name) {
        bail!("repository is outside the approved relay scope");
    }
    let git = p[0] == "git";
    let allowed = match p.as_slice() {
        ["git", _, _, "info", "refs"] => {
            method == "GET" && query == Some("service=git-upload-pack")
        }
        ["git", _, _, "git-upload-pack"] => method == "POST" && query.is_none(),
        ["api", "repos", _, _] => method == "GET" || method == "HEAD",
        ["api", "repos", _, _, "git", kind, ..] => {
            matches!(*kind, "refs" | "matching-refs") && matches!(method, "GET" | "HEAD")
        }
        ["api", "repos", _, _, kind, ..] => {
            matches!(
                *kind,

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Restrict requests to `/api/repos/{owner}/{repo}/...`, `/git/{owner}/{repo}/...`, or `/web/{owner}/{repo}/...` paths.
  2. Drop or replace unsupported endpoints (e.g. `/user`, `/search`) — they are outside the relay's read-only repo scope by design.
  3. Fix prefix typos and ensure the path is normalized (no leading host or scheme inside `path`).

Example fix

// before
let target = relay::operation("GET", "/user", None)?;
// after
let target = relay::operation("GET", "/api/repos/octocat/hello-world", None)?;
Defensive patterns

Strategy: validation

Validate before calling

fn relayable_path(p: &str) -> bool {
    let s: Vec<&str> = p.split('/').collect();
    matches!(s.as_slice(),
        ["api", "repos", _, _, ..] | ["git", _, _, ..] | ["web", _, _, ..])
}
assert!(relayable_path("/api/repos/o/r"));
assert!(!relayable_path("/user"));

Try / catch

match relay::operation("GET", path, None) {
    Err(e) if e.to_string().contains("unsupported GitHub operation") => eprintln!("endpoint not relayed: {path}"),
    Err(e) => return Err(e),
    Ok(t) => t,
}

Prevention

When it happens

Trigger: Calling `operation`/`forward` with paths like `/user`, `/orgs/foo`, `/api/graphql`, `/search/repositories`, a bare `/`, or a misspelled prefix like `/API/repos/...` or `/gits/owner/repo`.

Common situations: A client library building GitHub API URLs against endpoints the relay deliberately does not proxy (user, org, search, GraphQL); switching from download URLs to API endpoints the relay doesn't allow; typos in the prefix.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/4a3eb55eb678ec7f. Report an issue: GitHub.