{"record":{"id":"d02f6948f1a6248e","repo":"can1357/oh-my-pi","slug":"comments-idx-side-must-be-right-or-left","errorCode":null,"errorMessage":"comments[{idx}].side must be RIGHT or LEFT","messagePattern":"comments\\[(.+?)\\]\\.side must be RIGHT or LEFT","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"python/robomp/src/proxy/server.py","lineNumber":194,"sourceCode":"        raise HTTPException(400, f\"invalid '{field}': must be array of strings\")\n    return list(value)\n\n\ndef _require_review_comments(value: Any) -> list[dict[str, Any]]:\n    if value is None:\n        return []\n    if not isinstance(value, list):\n        raise HTTPException(400, \"missing/invalid 'comments'\")\n    comments: list[dict[str, Any]] = []\n    for idx, item in enumerate(value):\n        if not isinstance(item, dict):\n            raise HTTPException(400, f\"comments[{idx}] must be an object\")\n        path = _require_str(item.get(\"path\"), f\"comments[{idx}].path\")\n        line = _require_int(item.get(\"line\"), f\"comments[{idx}].line\")\n        body = _require_str(item.get(\"body\"), f\"comments[{idx}].body\")\n        side = str(item.get(\"side\") or \"RIGHT\")\n        if side not in (\"RIGHT\", \"LEFT\"):\n            raise HTTPException(400, f\"comments[{idx}].side must be RIGHT or LEFT\")\n        comment: dict[str, Any] = {\"path\": path, \"line\": line, \"side\": side, \"body\": body}\n        start_line = item.get(\"start_line\")\n        if start_line is not None:\n            comment[\"start_line\"] = _require_int(start_line, f\"comments[{idx}].start_line\")\n        start_side = item.get(\"start_side\")\n        if start_side is not None:\n            start_side_str = _require_str(start_side, f\"comments[{idx}].start_side\")\n            if start_side_str not in (\"RIGHT\", \"LEFT\"):\n                raise HTTPException(400, f\"comments[{idx}].start_side must be RIGHT or LEFT\")\n            comment[\"start_side\"] = start_side_str\n        comments.append(comment)\n    return comments\n\n\ndef _pool_dir(cfg: Settings, repo: str) -> Path:\n    _validate_repo_name(repo)\n    return Path(cfg.workspace_root) / \"_pool\" / repo.replace(\"/\", \"__\")\n","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/python/robomp/src/proxy/server.py#L176-L212","documentation":"Review comment `side` is optional and defaults to RIGHT, but if provided (after `str()` coercion) it must be exactly RIGHT or LEFT. Any other value raises this HTTP 400 for the offending comment index.","triggerScenarios":"submit_pr_review with a comment where `side` is e.g. \"right\" (lowercase), \"R\", \"SIDE_RIGHT\", or a numeric value whose str() is not RIGHT/LEFT.","commonSituations":"Clients using GitHub's full side vocabulary (e.g. \"RIGHT\" vs custom casing); confusion with GraphQL input enums; copy-pasted values from other APIs that accept PENDING as a side.","solutions":["Send exactly \"RIGHT\" or \"LEFT\" (uppercase), or omit `side` to get the RIGHT default.","Normalize casing client-side: side = raw.strip().upper() and only send if it is RIGHT or LEFT.","Drop PENDING or other extra enum values — this proxy only supports RIGHT/LEFT.","Ensure numeric fields are not accidentally landing in the side slot of the payload."],"exampleFix":"// before\n{\"path\": \"a.py\", \"line\": 3, \"body\": \"x\", \"side\": \"right\"}\n// after\n{\"path\": \"a.py\", \"line\": 3, \"body\": \"x\", \"side\": \"RIGHT\"}","handlingStrategy":"validation","validationCode":"side = raw.strip().upper() if raw else \"RIGHT\"\nif side not in (\"RIGHT\", \"LEFT\"):\n    raise ValueError(f\"side must be RIGHT or LEFT, got {raw!r}\")\ncomment[\"side\"] = side","typeGuard":"def is_valid_side(v: object) -> TypeGuard[str]:\n    return v in (\"RIGHT\", \"LEFT\")","tryCatchPattern":"try:\n    resp = http.post(f\"{base}/pr/{n}/review\", json=payload)\n    resp.raise_for_status()\nexcept httpx.HTTPStatusError as e:\n    if e.response.status_code == 400 and \".side must be\" in e.response.text:\n        raise ValueError(\"comment side must be exactly 'RIGHT' or 'LEFT'\") from e\n    raise","preventionTips":["Normalize casing before sending: side.strip().upper()","Omit side for the RIGHT default instead of inventing values","Keep the enum in a shared constant rather than inlining strings","Remember only RIGHT/LEFT are supported — PENDING etc. are rejected"],"tags":["http-400","input-validation","enum","github-api"],"backgroundTag":"request-parameter-validation","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}