{"record":{"id":"66eaf61ff6829d2b","repo":"can1357/oh-my-pi","slug":"missing-invalid-slot-uid","errorCode":null,"errorMessage":"missing/invalid 'slot_uid'","messagePattern":"missing/invalid 'slot_uid'","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"python/robomp/src/proxy/server.py","lineNumber":168,"sourceCode":"    branch = _require_fetch_ref(value)\n    return branch.removeprefix(\"refs/heads/\")\n\n\n_RELEASE_TAG_RE = re.compile(r\"v[0-9][A-Za-z0-9._-]*\")\n\n\ndef _require_release_tag(value: Any) -> str:\n    tag = _require_str(value, \"tag\")\n    if not _RELEASE_TAG_RE.fullmatch(tag):\n        raise HTTPException(400, \"invalid tag\")\n    return tag\n\n\ndef _optional_slot_uid(value: Any) -> int | None:\n    if value is None:\n        return None\n    if not isinstance(value, int) or isinstance(value, bool) or not (0 < value < 65536):\n        raise HTTPException(400, \"missing/invalid 'slot_uid'\")\n    return value\n\n\ndef _optional_str_list(value: Any, field: str) -> list[str] | None:\n    if value is None:\n        return None\n    if not isinstance(value, list) or not all(isinstance(v, str) for v in value):\n        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):","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/python/robomp/src/proxy/server.py#L150-L186","documentation":"The gh-proxy validates the optional `slot_uid` body/query parameter with `_optional_slot_uid`. If supplied, it must be a strict integer strictly between 0 and 65536 (booleans rejected). Any missing-or-invalid value raises this HTTP 400 before the request reaches the git push logic.","triggerScenarios":"Calling git_push_endpoint or git_push_release_endpoint with `slot_uid` set to a bool (true/false), a string like \"12\", a float, a negative number, 0, or an integer >= 65536.","commonSituations":"Clients JSON-encode slot ids as strings from config files or environment variables; frontends send booleans because slot ids are modeled as flags; ids out of the 16-bit port-like range are used by custom sandbox allocators.","solutions":["Send `slot_uid` as a JSON number in the range 1..65535 (e.g. 42, not \"42\"), or omit the field entirely if no slot is targeted.","On the client, coerce with care: `slot_uid = int(raw)` and re-check `0 < slot_uid < 65536` before sending.","Remove `true`/`false` values — Python's isinstance(value, bool) check rejects them even though bool subclasses int.","If the field is not needed by your flow, drop it from the payload instead of sending null-come-string placeholders."],"exampleFix":"// before\ncurl -X POST .../git/push -d '{\"slot_uid\": \"12\", ...}'\n// after\ncurl -X POST .../git/push -d '{\"slot_uid\": 12, ...}'","handlingStrategy":"validation","validationCode":"def valid_slot_uid(v):\n    return isinstance(v, int) and not isinstance(v, bool) and 0 < v < 65536\n\npayload = {\"slot_uid\": int(cfg.slot_id)} if valid_slot_uid(cfg.slot_id) else {}","typeGuard":"def is_slot_uid(v: object) -> TypeGuard[int]:\n    return isinstance(v, int) and not isinstance(v, bool) and 0 < v < 65536","tryCatchPattern":"try:\n    resp = http.post(f\"{base}/git/push\", json=payload)\n    resp.raise_for_status()\nexcept httpx.HTTPStatusError as e:\n    if e.response.status_code == 400 and \"slot_uid\" in e.response.text:\n        raise ValueError(\"slot_uid must be an int in 1..65535\") from e\n    raise","preventionTips":["Keep slot ids as ints end-to-end; never round-trip them through strings","Explicitly exclude bools when generating ids from flag-like config","Centralize payload building so slot_uid is validated once","Omit the field instead of sending null/placeholder values when unused"],"tags":["http-400","input-validation","fastapi","proxy"],"backgroundTag":"request-parameter-validation","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}