{"record":{"id":"eb21a58aa5e0a9dc","repo":"can1357/oh-my-pi","slug":"invalid-state-state-r","errorCode":null,"errorMessage":"invalid state: {state!r}","messagePattern":"invalid state: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/robomp/src/github_client.py","lineNumber":537,"sourceCode":"            if len(batch) < 100:\n                return files\n            page += 1\n\n    async def list_issues(\n        self,\n        repo: str,\n        *,\n        state: str = \"open\",\n        limit: int = 30,\n    ) -> list[IssueSummary]:\n        \"\"\"List recent issues for `repo`, newest-updated first. Excludes pull requests.\n\n        `state` is one of `open`, `closed`, `all`. `limit` is capped at 100 by the\n        GitHub `per_page`; we don't paginate here — the dashboard browse view shows\n        a recent slice, not every issue ever.\n        \"\"\"\n        if state not in (\"open\", \"closed\", \"all\"):\n            raise ValueError(f\"invalid state: {state!r}\")\n        per_page = max(1, min(int(limit), 100))\n        data = await self.request(\n            \"GET\",\n            f\"/repos/{repo}/issues\",\n            params={\"state\": state, \"per_page\": per_page, \"sort\": \"updated\", \"direction\": \"desc\"},\n        )\n        out: list[IssueSummary] = []\n        for item in data or []:\n            if \"pull_request\" in item:\n                continue  # GitHub's /issues endpoint also returns PRs; skip them.\n            out.append(_summary_from_item(repo, item))\n        return out\n\n    async def search_issues(self, repo: str, query: str, *, limit: int = 10) -> list[IssueSummary]:\n        \"\"\"Search issues AND pull requests in `repo` using GitHub issue-search syntax.\n\n        `query` takes bare keywords plus qualifiers (`is:pr`, `is:closed`,\n        `label:bug`, `in:title`, …); the `repo:` scope is applied here. Results","sourceCodeStart":519,"sourceCodeEnd":555,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/python/robomp/src/github_client.py#L519-L555","documentation":"ValueError from list_issues when the `state` argument is not exactly one of \"open\", \"closed\", or \"all\". It is a client-side validation guard run before any HTTP request.","triggerScenarios":"Passing states like \"Open\", \"OPEN\", \"opened\", None, or other arbitrary strings to list_issues.","commonSituations":"Mapping a UI dropdown or config value straight into the API param; upstream code using a different issue-state vocabulary (e.g. \"opened\" from webhook payloads).","solutions":["Pass exactly \"open\", \"closed\", or \"all\" (lowercase)","Normalize/whitelist the value before calling list_issues"],"exampleFix":"// before\nissues = await client.list_issues(repo, state=\"opened\")\n// after\nissues = await client.list_issues(repo, state=\"open\" if state == \"opened\" else state)","handlingStrategy":"validation","validationCode":"VALID_STATES = {\"open\", \"closed\", \"all\"}\nif state not in VALID_STATES:\n    raise ValueError(f\"state must be one of {sorted(VALID_STATES)}, got {state!r}\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Normalize synonyms (\"opened\" -> \"open\") before calling","Keep the state value in a Literal[\"open\",\"closed\",\"all\"] typed variable","Add a whitelist check at the config/UI boundary"],"tags":["validation","argument-error","github"],"backgroundTag":"invalid-argument-value","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}