can1357/oh-my-pi · error · HTTPException

timeout reading origin url

Error message

timeout reading origin url

What it means

This 504 error is raised by the gh-proxy when spawning `git remote get-url origin` in a worktree takes longer than _ORIGIN_READ_TIMEOUT_SECONDS. The proxy deliberately wraps subprocess.TimeoutExpired into an HTTP 504 so the client knows the origin lookup timed out rather than failed. It indicates the local git command hung, typically because the repository lives on slow/locked storage or git is blocked on a credential/SSH prompt.

Source

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


def _read_remote_urls(repo_dir: Path, slot_uid: int | None = None, *, push: bool = False) -> list[str]:
    """Read every configured fetch URL or push URL for `origin` without contacting it."""
    env = _git_probe_env(repo_dir)
    slot_kwargs = _slot_subprocess_kwargs(slot_uid)
    selector = ["--push", "--all"] if push else ["--all"]
    try:
        proc = subprocess.run(
            ["git", "-C", str(repo_dir), "remote", "get-url", *selector, "origin"],
            capture_output=True,
            text=True,
            check=False,
            timeout=_ORIGIN_READ_TIMEOUT_SECONDS,
            env=env,
            **slot_kwargs,
        )
    except subprocess.TimeoutExpired as exc:
        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")

View on GitHub (pinned to 9690622007)

Solutions

  1. Retry the request — transient stalls (mount latency, load) often resolve; keep retries bounded
  2. Check that the repo_dir path is on fast local storage and not a stale/hung network mount
  3. Disable interactive git prompts for the proxy env (GIT_TERMINAL_PROMPT=0, GIT_ASKPASS=echo) so git cannot block on credentials
  4. Inspect `git -C <repo_dir> remote get-url origin` manually to reproduce and time the hang
  5. If hangs are chronic, run the git lookup out-of-band (cache remote urls) instead of per-request

Example fix

// before (server env allows git to prompt, causing hangs)
env = {"PATH": os.environ["PATH"]}
// after (block interactive prompts so git fails fast instead of hanging)
env = {"PATH": os.environ["PATH"], "GIT_TERMINAL_PROMPT": "0", "GIT_ASKPASS": "/bin/true"}
Defensive patterns

Strategy: retry

Validate before calling

import subprocess

def origin_lookup_is_fast(repo_dir: str, timeout_s: float = 5.0) -> bool:
    try:
        subprocess.run(["git", "-C", repo_dir, "remote", "get-url", "origin"],
                       timeout=timeout_s, capture_output=True, check=False)
        return True
    except subprocess.TimeoutExpired:
        return False

Try / catch

import httpx
from fastapi import HTTPException

for attempt in range(3):
    try:
        return client.post("/git/op", json={"repo": "acme/repo"})
    except HTTPException as e:
        if e.status_code != 504 or attempt == 2:
            raise

Prevention

When it happens

Trigger: Calling a proxy git endpoint whose handler calls _read_single_remote_url → _read_remote_urls when `git remote get-url origin` (optionally with push or a slot uid via slot_kwargs) does not exit within _ORIGIN_READ_TIMEOUT_SECONDS and subprocess raises TimeoutExpired.

Common situations: NFS/lazy-mounted repo directories stalling git; a git credential helper blocking on an interactive prompt; core.hooksPath or insteadOf config invoking something slow; heavy system load or a wedged filesystem; an alias/wrapper intercepting git.

Understand the failure class

Related errors


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