can1357/oh-my-pi · error · HTTPException

workspace_key does not match repo

Error message

workspace_key does not match repo

What it means

The `git_push_endpoint` validates that the caller-supplied `workspace_key` starts with `<owner>__<repo>__` — the naming scheme the proxy uses to bind workspaces to repositories. If the key does not match the `repo` field in the same request, the proxy rejects it with HTTP 400 to prevent pushing a workspace's repo to a different GitHub target.

Source

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

                remote_url=remote.url,
                auth_url=remote.auth_url,
            )
        except GitCommandError as exc:
            return _git_error_response(exc)
        return JSONResponse({"pool_dir": str(target)})

    @app.post("/gh/v1/git/push")
    async def git_push_endpoint(request: Request) -> JSONResponse:
        data = await _json_body(request)
        repo = _require_str(data.get("repo"), "repo")
        workspace_key = _require_str(data.get("workspace_key"), "workspace_key")
        branch = _require_branch(data.get("branch"))
        expected_head = _require_str(data.get("expected_head"), "expected_head")
        slot_uid = _optional_slot_uid(data.get("slot_uid"))
        # Sanity-check workspace_key matches the repo claim.
        expected_prefix = repo.replace("/", "__") + "__"
        if not workspace_key.startswith(expected_prefix):
            raise HTTPException(400, "workspace_key does not match repo")
        repo_dir = _workspace_repo_dir(settings, workspace_key)
        if not repo_dir.is_dir():
            raise HTTPException(404, f"workspace not found: {workspace_key}")
        remote = await asyncio.to_thread(
            _origin_remote_auth,
            repo_dir,
            repo,
            _resolve_token(settings),
            push=True,
            slot_uid=slot_uid,
        )
        try:
            result = await _run_git_op(
                git_push,
                repo_dir,
                branch=branch,
                expected_head=expected_head,
                token=remote.token,

View on GitHub (pinned to 9690622007)

Solutions

  1. Use the workspace_key exactly as returned when the workspace was created, and set `repo` to the repo that workspace belongs to
  2. Check that `repo.replace('/', '__') + '__'` is a prefix of your workspace_key; fix whichever field is wrong
  3. If the repo was renamed/transferred, create a new workspace for the new repo identity

Example fix

// before
{ "repo": "owner/other-repo", "workspace_key": "owner__name__task1" }
// after
{ "repo": "owner/name", "workspace_key": "owner__name__task1" }
Defensive patterns

Strategy: validation

Validate before calling

def check_workspace_matches(repo: str, workspace_key: str) -> None:
    prefix = repo.replace("/", "__") + "__"
    if not workspace_key.startswith(prefix):
        raise ValueError(f"workspace_key {workspace_key!r} does not belong to repo {repo!r}")
check_workspace_matches(repo, workspace_key)

Try / catch

try:
    proxy.git_push(repo=repo, workspace_key=key, ...)
except HTTPError as e:
    if e.response.status_code == 400 and "workspace_key does not match repo" in e.response.text:
        raise ValueError(f"workspace {key} is not bound to {repo}; use the key returned at workspace creation") from e
    raise

Prevention

When it happens

Trigger: POSTing to /gh/v1/git/push with a `repo` like `owner/name` but a `workspace_key` that does not begin with `owner__name__` — e.g. a workspace key belonging to another repo, a typo'd repo field, or a hand-constructed workspace_key.

Common situations: Copy-pasting a workspace_key from one task/session into a push request for a different repo, renaming/moving the repo (owner transfer) while workspace keys keep the old prefix, or constructing keys manually instead of from the workspace creation response.

Related errors


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