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
- Restrict requests to `/api/repos/{owner}/{repo}/...`, `/git/{owner}/{repo}/...`, or `/web/{owner}/{repo}/...` paths.
- Drop or replace unsupported endpoints (e.g. `/user`, `/search`) — they are outside the relay's read-only repo scope by design.
- 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
- Restrict client code to repo-scoped API endpoints the relay supports.
- Keep a list of relayed path prefixes and route other GitHub calls outside the relay.
- Normalize paths before calling (no host/scheme, correct casing for prefixes).
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
- unsupported query parameter
- unsupported relay host
- relay concurrency must be between 1 and 32
- expected a GitHub repository in OWNER/REPO form
- repository is outside the approved relay scope
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/4a3eb55eb678ec7f.
Report an issue: GitHub.