can1357/oh-my-pi · error · HTTPException

origin must have exactly one {kind} url

Error message

origin must have exactly one {kind} url

What it means

Raised when `git remote get-url origin` returns zero or multiple URLs for origin instead of exactly one. git can return several lines when a remote has multiple URLs configured (url multi-valued via `remote.origin.url` or multiple pushurl entries). The proxy requires an unambiguous single fetch/push URL to authenticate against GitHub.

Source

Thrown at python/robomp/src/proxy/server.py:310

        raise HTTPException(504, "timeout reading origin url") from exc
    if proc.returncode != 0:
        # `git remote get-url` writes nothing useful to stdout on failure; do
        # NOT echo stderr to the client (may leak local paths). The proxy log
        # already captured the failure.
        log.warning("gh-proxy: failed to read origin url", extra={"repo_dir": str(repo_dir)})
        raise HTTPException(400, "could not read origin url for worktree")
    return [line.strip() for line in proc.stdout.splitlines() if line.strip()]


def _read_single_remote_url(repo_dir: Path, expected_repo: str, *, push: bool, slot_uid: int | None = None) -> str:
    urls = list(dict.fromkeys(_read_remote_urls(repo_dir, slot_uid=slot_uid, push=push)))
    if len(urls) != 1:
        kind = "push" if push else "fetch"
        log.warning(
            "gh-proxy: refusing git op — origin has ambiguous remote urls",
            extra={"expected_repo": expected_repo, "kind": kind, "count": len(urls)},
        )
        raise HTTPException(400, f"origin must have exactly one {kind} url")
    return urls[0]


def _normalized_github_https_url(url: str, expected_repo: str) -> str:
    _validate_repo_name(expected_repo)
    parsed = urlparse(url)
    if (parsed.scheme or "").lower() != "https":
        raise HTTPException(400, f"remote url must be https://github.com/{expected_repo}[.git]")
    if parsed.username or parsed.password:
        raise HTTPException(400, "remote url must not contain embedded credentials")
    try:
        port = parsed.port
    except ValueError as exc:
        raise HTTPException(400, "remote url has invalid port") from exc
    if port is not None:
        raise HTTPException(400, "remote url must not specify a port")
    if (parsed.hostname or "").lower() != "github.com":
        raise HTTPException(400, f"remote url host must be github.com for repo {expected_repo!r}")

View on GitHub (pinned to 9690622007)

Solutions

  1. Inspect `git config --get-all remote.origin.url` and `git config --get-all remote.origin.pushurl` in the worktree
  2. Collapse to a single URL: `git remote set-url origin <url>` and remove extra pushurls with `git config --unset-all remote.origin.pushurl` (or `git remote set-url --delete --push origin <extra>`)
  3. If you need push/fan-out remotes, configure them on a different remote name, not origin
  4. Re-add the remote cleanly: `git remote remove origin && git remote add origin <url>`

Example fix

// before: multiple push urls on origin
$ git remote set-url --add --push origin https://github.com/acme/mirror.git
// after: single url, move extra pushes elsewhere
$ git remote set-url --delete --push origin https://github.com/acme/mirror.git
$ git remote add mirror https://github.com/acme/mirror.git
Defensive patterns

Strategy: validation

Validate before calling

import subprocess

def origin_has_single_url(repo_dir: str) -> bool:
    urls = subprocess.run(["git", "-C", repo_dir, "config", "--get-all", "remote.origin.url"],
                          capture_output=True, text=True, check=False).stdout.split()
    return len(urls) == 1

Try / catch

from fastapi import HTTPException

try:
    result = client.post("/git/op", json={"repo": "acme/repo"})
except HTTPException as e:
    if e.status_code == 400 and "exactly one" in e.detail:
        normalize_origin_remote(worktree_dir)  # collapse multi-url origin
    else:
        raise

Prevention

When it happens

Trigger: A git operation via the proxy where _read_single_remote_url finds the deduplicated URL list length != 1 for the requested kind (fetch or push): origin configured with multiple pushURLs, or a broken empty remote with no url.

Common situations: `git remote set-url --add --push origin <url>` used for split push/pull setups (e.g. push to a mirror); multi-remote relay configs copied into origin; a remote whose url entry was removed leaving zero urls.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/cb3bbcfb086a20f9. Report an issue: GitHub.