can1357/oh-my-pi · error · HTTPException
comments[{idx}].side must be RIGHT or LEFT
Error message
comments[{idx}].side must be RIGHT or LEFT What it means
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.
Source
Thrown at python/robomp/src/proxy/server.py:194
raise HTTPException(400, f"invalid '{field}': must be array of strings")
return list(value)
def _require_review_comments(value: Any) -> list[dict[str, Any]]:
if value is None:
return []
if not isinstance(value, list):
raise HTTPException(400, "missing/invalid 'comments'")
comments: list[dict[str, Any]] = []
for idx, item in enumerate(value):
if not isinstance(item, dict):
raise HTTPException(400, f"comments[{idx}] must be an object")
path = _require_str(item.get("path"), f"comments[{idx}].path")
line = _require_int(item.get("line"), f"comments[{idx}].line")
body = _require_str(item.get("body"), f"comments[{idx}].body")
side = str(item.get("side") or "RIGHT")
if side not in ("RIGHT", "LEFT"):
raise HTTPException(400, f"comments[{idx}].side must be RIGHT or LEFT")
comment: dict[str, Any] = {"path": path, "line": line, "side": side, "body": body}
start_line = item.get("start_line")
if start_line is not None:
comment["start_line"] = _require_int(start_line, f"comments[{idx}].start_line")
start_side = item.get("start_side")
if start_side is not None:
start_side_str = _require_str(start_side, f"comments[{idx}].start_side")
if start_side_str not in ("RIGHT", "LEFT"):
raise HTTPException(400, f"comments[{idx}].start_side must be RIGHT or LEFT")
comment["start_side"] = start_side_str
comments.append(comment)
return comments
def _pool_dir(cfg: Settings, repo: str) -> Path:
_validate_repo_name(repo)
return Path(cfg.workspace_root) / "_pool" / repo.replace("/", "__")
View on GitHub (pinned to 9690622007)
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.
Example fix
// before
{"path": "a.py", "line": 3, "body": "x", "side": "right"}
// after
{"path": "a.py", "line": 3, "body": "x", "side": "RIGHT"} Defensive patterns
Strategy: validation
Validate before calling
side = raw.strip().upper() if raw else "RIGHT"
if side not in ("RIGHT", "LEFT"):
raise ValueError(f"side must be RIGHT or LEFT, got {raw!r}")
comment["side"] = side Type guard
def is_valid_side(v: object) -> TypeGuard[str]:
return v in ("RIGHT", "LEFT") Try / catch
try:
resp = http.post(f"{base}/pr/{n}/review", json=payload)
resp.raise_for_status()
except httpx.HTTPStatusError as e:
if e.response.status_code == 400 and ".side must be" in e.response.text:
raise ValueError("comment side must be exactly 'RIGHT' or 'LEFT'") from e
raise Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- comments[{idx}].start_side must be RIGHT or LEFT
- missing/invalid 'comments'
- comments[{idx}] must be an object
- missing/invalid 'slot_uid'
- invalid '{field}': must be array of strings
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/d02f6948f1a6248e.
Report an issue: GitHub.