{"record":{"id":"153b6db701f23238","repo":"can1357/oh-my-pi","slug":"github-token-and-robomp-gh-proxy-url-are-mutually","errorCode":null,"errorMessage":"GITHUB_TOKEN and ROBOMP_GH_PROXY_URL are mutually exclusive — set ONE to choose between direct-PAT and gh-proxy modes.","messagePattern":"GITHUB_TOKEN and ROBOMP_GH_PROXY_URL are mutually exclusive — set ONE to choose between direct-PAT and gh-proxy modes\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/robomp/src/config.py","lineNumber":242,"sourceCode":"            if isinstance(inner, str) and not inner.strip():\n                return None\n        return value\n\n    @model_validator(mode=\"after\")\n    def _validate_proxy_or_pat(self) -> Settings:\n        \"\"\"Enforce mutual exclusion between PAT and proxy mode.\n\n        - Both set → reject (silent fallback to direct GitHub would defeat\n          the isolation goal).\n        - Proxy URL set but no HMAC key (or vice versa) → reject (gh-proxy\n          would either be unauthenticated or unreachable).\n        - Neither set → also reject; SOMETHING needs to talk to GitHub.\n        \"\"\"\n        has_token = self.github_token is not None\n        has_url = bool(self.gh_proxy_url)\n        has_key = self.gh_proxy_hmac_key is not None\n        if has_token and has_url:\n            raise ValueError(\n                \"GITHUB_TOKEN and ROBOMP_GH_PROXY_URL are mutually exclusive — \"\n                \"set ONE to choose between direct-PAT and gh-proxy modes.\"\n            )\n        if has_url != has_key:\n            raise ValueError(\n                \"ROBOMP_GH_PROXY_URL and ROBOMP_GH_PROXY_HMAC_KEY must both be set together (or both empty).\"\n            )\n        if not has_token and not has_url:\n            raise ValueError(\n                \"no GitHub access configured: set GITHUB_TOKEN, or set \"\n                \"ROBOMP_GH_PROXY_URL + ROBOMP_GH_PROXY_HMAC_KEY to use gh-proxy.\"\n            )\n        return self\n\n    @field_validator(\"repo_allowlist_raw\", mode=\"before\")\n    @classmethod\n    def _coerce_allowlist(cls, v: object) -> str:\n        if v is None:","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/python/robomp/src/config.py#L224-L260","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Remove GITHUB_TOKEN from the environment when using gh-proxy mode.","Or remove ROBOMP_GH_PROXY_URL/ROBOMP_GH_PROXY_HMAC_KEY when using direct-PAT mode.","Audit env layering (.env, shell, container env, CI) for stray variables.","Print effective config (redacted) at startup to catch mixed modes early."],"exampleFix":"// before\nGITHUB_TOKEN=ghp_xxx\nROBOMP_GH_PROXY_URL=http://gh-proxy:8080\n// after (proxy mode)\nROBOMP_GH_PROXY_URL=http://gh-proxy:8080\nROBOMP_GH_PROXY_HMAC_KEY=<key>","handlingStrategy":"validation","validationCode":"import os\nmode = sum(bool(x) for x in (os.environ.get(\"GITHUB_TOKEN\"), os.environ.get(\"ROBOMP_GH_PROXY_URL\")))\nif mode > 1:\n    raise SystemExit(\"Set exactly one GitHub access mode: GITHUB_TOKEN or the gh-proxy pair\")","typeGuard":"def has_single_github_mode(env: dict) -> bool:\n    return bool(env.get(\"GITHUB_TOKEN\")) != bool(env.get(\"ROBOMP_GH_PROXY_URL\"))","tryCatchPattern":"try:\n    cfg = Settings(_env_file=\".env\")\nexcept ValidationError as exc:\n    sys.exit(f\"configuration error: {exc}\")","preventionTips":["When migrating between PAT and proxy modes, delete the old variable, don't just add new ones.","Audit env layering (shell profile, CI globals, container env) for stray GITHUB_TOKEN.","Keep one canonical .env per deployment mode."],"tags":["python","configuration","validation","pydantic","github"],"backgroundTag":"invalid-environment-configuration","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}