{"record":{"id":"62738ac98e97a8a4","repo":"can1357/oh-my-pi","slug":"could-not-read-origin-url-for-worktree","errorCode":null,"errorMessage":"could not read origin url for worktree","messagePattern":"could not read origin url for worktree","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"python/robomp/src/proxy/server.py","lineNumber":298,"sourceCode":"    selector = [\"--push\", \"--all\"] if push else [\"--all\"]\n    try:\n        proc = subprocess.run(\n            [\"git\", \"-C\", str(repo_dir), \"remote\", \"get-url\", *selector, \"origin\"],\n            capture_output=True,\n            text=True,\n            check=False,\n            timeout=_ORIGIN_READ_TIMEOUT_SECONDS,\n            env=env,\n            **slot_kwargs,\n        )\n    except subprocess.TimeoutExpired as exc:\n        raise HTTPException(504, \"timeout reading origin url\") from exc\n    if proc.returncode != 0:\n        # `git remote get-url` writes nothing useful to stdout on failure; do\n        # NOT echo stderr to the client (may leak local paths). The proxy log\n        # already captured the failure.\n        log.warning(\"gh-proxy: failed to read origin url\", extra={\"repo_dir\": str(repo_dir)})\n        raise HTTPException(400, \"could not read origin url for worktree\")\n    return [line.strip() for line in proc.stdout.splitlines() if line.strip()]\n\n\ndef _read_single_remote_url(repo_dir: Path, expected_repo: str, *, push: bool, slot_uid: int | None = None) -> str:\n    urls = list(dict.fromkeys(_read_remote_urls(repo_dir, slot_uid=slot_uid, push=push)))\n    if len(urls) != 1:\n        kind = \"push\" if push else \"fetch\"\n        log.warning(\n            \"gh-proxy: refusing git op — origin has ambiguous remote urls\",\n            extra={\"expected_repo\": expected_repo, \"kind\": kind, \"count\": len(urls)},\n        )\n        raise HTTPException(400, f\"origin must have exactly one {kind} url\")\n    return urls[0]\n\n\ndef _normalized_github_https_url(url: str, expected_repo: str) -> str:\n    _validate_repo_name(expected_repo)\n    parsed = urlparse(url)","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/python/robomp/src/proxy/server.py#L280-L316","documentation":"Raised when `git remote get-url origin` exits non-zero in the given worktree. The proxy cannot discover the origin URL, so it refuses the git operation with HTTP 400. stderr is intentionally not echoed to the client to avoid leaking local paths; details are only in the proxy log.","triggerScenarios":"Calling any proxy git endpoint that resolves the worktree's origin when: repo_dir is not a git repository, the `origin` remote does not exist, git is missing/misconfigured for the spawned env, or the worktree is corrupted.","commonSituations":"Pointing the proxy at a directory that was never `git init`ed or was checked out with a remote other than `origin`; deleted .git directory; worktree metadata pruned; GIT_DIR/GIT_CONFIG env in slot_kwargs overriding config; git not on PATH in the proxy environment.","solutions":["Run `git -C <worktree> remote get-url origin` yourself to see the real failure (the client response hides stderr)","Ensure the directory is a valid git repo/worktree with an `origin` remote; add one via `git remote add origin <url>` if missing","Verify git is installed and on PATH for the proxy process environment","Check proxy logs (log.warning 'gh-proxy: failed to read origin url') for the underlying git stderr","Re-create the worktree if its .git metadata is corrupted"],"exampleFix":"// before: repo without origin remote\n$ git -C /srv/worktrees/feat origin  # error: No such remote 'origin'\n// after\n$ git -C /srv/worktrees/feat remote add origin https://github.com/acme/repo.git","handlingStrategy":"validation","validationCode":"import subprocess\n\ndef worktree_has_origin(repo_dir: str) -> bool:\n    r = subprocess.run([\"git\", \"-C\", repo_dir, \"remote\", \"get-url\", \"origin\"],\n                       capture_output=True, check=False)\n    return r.returncode == 0","typeGuard":null,"tryCatchPattern":"from fastapi import HTTPException\n\ntry:\n    result = client.post(\"/git/op\", json={\"repo\": \"acme/repo\"})\nexcept HTTPException as e:\n    if e.status_code == 400 and \"could not read origin url\" in e.detail:\n        fix_worktree_origin(worktree_dir)  # add origin or recreate worktree\n    else:\n        raise","preventionTips":["Always create proxy-managed worktrees with an `origin` remote","Validate repo_dir with `git rev-parse --is-inside-work-tree` before proxy calls","Pin git availability/PATH in the proxy deployment","Check proxy logs for the underlying git stderr when onboarding new worktrees"],"tags":["git","remote","proxy","configuration"],"backgroundTag":"missing-git-remote","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}