can1357/oh-my-pi · error · ValueError

GITHUB_TOKEN and ROBOMP_GH_PROXY_URL are mutually exclusive

Error message

GITHUB_TOKEN and ROBOMP_GH_PROXY_URL are mutually exclusive — set ONE to choose between direct-PAT and gh-proxy modes.

What it means

The Settings model validator _validate_proxy_or_pat() enforces exactly one GitHub access mode: a direct PAT (GITHUB_TOKEN) or the gh-proxy pair (ROBOMP_GH_PROXY_URL + HMAC key). Setting both is ambiguous and rejected with ValueError during model validation.

Source

Thrown at python/robomp/src/config.py:242

            if isinstance(inner, str) and not inner.strip():
                return None
        return value

    @model_validator(mode="after")
    def _validate_proxy_or_pat(self) -> Settings:
        """Enforce mutual exclusion between PAT and proxy mode.

        - Both set → reject (silent fallback to direct GitHub would defeat
          the isolation goal).
        - Proxy URL set but no HMAC key (or vice versa) → reject (gh-proxy
          would either be unauthenticated or unreachable).
        - Neither set → also reject; SOMETHING needs to talk to GitHub.
        """
        has_token = self.github_token is not None
        has_url = bool(self.gh_proxy_url)
        has_key = self.gh_proxy_hmac_key is not None
        if has_token and has_url:
            raise ValueError(
                "GITHUB_TOKEN and ROBOMP_GH_PROXY_URL are mutually exclusive — "
                "set ONE to choose between direct-PAT and gh-proxy modes."
            )
        if has_url != has_key:
            raise ValueError(
                "ROBOMP_GH_PROXY_URL and ROBOMP_GH_PROXY_HMAC_KEY must both be set together (or both empty)."
            )
        if not has_token and not has_url:
            raise ValueError(
                "no GitHub access configured: set GITHUB_TOKEN, or set "
                "ROBOMP_GH_PROXY_URL + ROBOMP_GH_PROXY_HMAC_KEY to use gh-proxy."
            )
        return self

    @field_validator("repo_allowlist_raw", mode="before")
    @classmethod
    def _coerce_allowlist(cls, v: object) -> str:
        if v is None:

View on GitHub (pinned to 9690622007)

Solutions

  1. Remove GITHUB_TOKEN from the environment when using gh-proxy mode.
  2. Or remove ROBOMP_GH_PROXY_URL/ROBOMP_GH_PROXY_HMAC_KEY when using direct-PAT mode.
  3. Audit env layering (.env, shell, container env, CI) for stray variables.
  4. Print effective config (redacted) at startup to catch mixed modes early.

Example fix

// before
GITHUB_TOKEN=ghp_xxx
ROBOMP_GH_PROXY_URL=http://gh-proxy:8080
// after (proxy mode)
ROBOMP_GH_PROXY_URL=http://gh-proxy:8080
ROBOMP_GH_PROXY_HMAC_KEY=<key>
Defensive patterns

Strategy: validation

Validate before calling

import os
mode = sum(bool(x) for x in (os.environ.get("GITHUB_TOKEN"), os.environ.get("ROBOMP_GH_PROXY_URL")))
if mode > 1:
    raise SystemExit("Set exactly one GitHub access mode: GITHUB_TOKEN or the gh-proxy pair")

Type guard

def has_single_github_mode(env: dict) -> bool:
    return bool(env.get("GITHUB_TOKEN")) != bool(env.get("ROBOMP_GH_PROXY_URL"))

Try / catch

try:
    cfg = Settings(_env_file=".env")
except ValidationError as exc:
    sys.exit(f"configuration error: {exc}")

Prevention

When it happens

Trigger: Constructing Settings (from env or programmatically) with both github_token and gh_proxy_url set — e.g. GITHUB_TOKEN present in base env plus ROBOMP_GH_PROXY_URL in a .env file.

Common situations: Migrating from direct-PAT to gh-proxy mode without removing the old token; inheriting host env into containers; CI injecting GITHUB_TOKEN globally while the job configures proxy mode.

Related errors


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