{"record":{"id":"e310e98a635c846e","repo":"sgl-project/sglang","slug":"duplicate-request-id-detected-rid","errorCode":null,"errorMessage":"Duplicate request ID detected: {rid}","messagePattern":"Duplicate request ID detected: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/managers/tokenizer_manager.py","lineNumber":3427,"sourceCode":"        if not hasattr(obj, \"is_single\") or obj.is_single:\n            items = [(obj.rid, obj, getattr(obj, \"bootstrap_room\", None))]\n        else:\n            items = [\n                (\n                    obj.rid[i],\n                    obj[i],\n                    (\n                        obj.bootstrap_room[i]\n                        if hasattr(obj, \"bootstrap_room\") and obj.bootstrap_room\n                        else None\n                    ),\n                )\n                for i in range(len(obj.rid))\n            ]\n\n        for rid, sub_obj, bootstrap_room in items:\n            if rid in self.rid_to_state:\n                raise ValueError(f\"Duplicate request ID detected: {rid}\")\n            time_stats = APIServerReqTimeStats(disagg_mode=self.disaggregation_mode)\n            state = ReqState([], False, asyncio.Event(), sub_obj, time_stats)\n            self.rid_to_state[rid] = state\n            if self.enable_trace:\n                time_stats.init_trace_ctx(rid, bootstrap_room, external_trace_header)\n            time_stats.set_created_time(created_time)\n\n    def _discard_pending_req_states(self, obj):\n        \"\"\"Drop rid_to_state entries created by _init_req_state for *obj*.\n\n        Safe to call after a partial/failed dispatch: only entries still present\n        are removed, and the scheduler-response path looks up state with\n        ``.get(...)`` so a later output for a discarded rid is ignored, not fatal.\n        \"\"\"\n        if not hasattr(obj, \"is_single\") or obj.is_single:\n            rids = [obj.rid]\n        else:\n            rids = obj.rid","sourceCodeStart":3409,"sourceCodeEnd":3445,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/managers/tokenizer_manager.py#L3409-L3445","documentation":"The tokenizer manager tracks every in-flight request by request ID (rid_to_state) and rejects any rid that already has live state. A second request reusing an active rid (not yet finished/aborted) triggers this error.","triggerScenarios":"Sending /generate or batch requests where rid duplicates an ID whose state hasn't been cleaned up yet; common with retry logic that reuses generated IDs or client-side fixed IDs, and in batch arrays containing repeated rids.","commonSituations":"Retries after timeout while original request still processing; batch requests containing the same rid twice; client ID generators with collisions (timestamp seeds, non-unique uuid variants); tests reusing rid constants.","solutions":["Let the client generate a fresh rid (e.g. uuid4) per request and per retry","For batches, verify rid uniqueness within the array before sending","If a rid is stuck, abort the original request or wait for finish before resubmitting (see test_abort_allallows_resubmit_same_rid: abort clears the state)"],"exampleFix":"# before\nrid = \"fixed-id\"  # reused across retries\nresponse = client.generate(prompt, rid=rid)\n\n# after\nimport uuid\nrid = str(uuid.uuid4())  # fresh per attempt\nresponse = client.generate(prompt, rid=rid)","handlingStrategy":"type-guard","validationCode":"import uuid\nrid = rid or str(uuid.uuid4())\nif rid in in_flight_rids_local:\n    rid = str(uuid.uuid4())","typeGuard":"def unique_rids(reqs: list[dict]) -> bool:\n    ids = [r.get(\"rid\") or str(uuid.uuid4()) for r in reqs]\n    return len(ids) == len(set(ids))","tryCatchPattern":"try:\n    out = engine.generate(prompt, rid=rid)\nexcept ValueError as e:\n    if \"Duplicate request ID\" in str(e):\n        out = engine.generate(prompt, rid=str(uuid.uuid4()))\n    else:\n        raise","preventionTips":["Always let the server/client mint rid via uuid unless idempotency requires otherwise","On retries, generate a new rid or first abort the original","For batch APIs, assert uniqueness of rid within the payload"],"tags":["request-id","duplicate","retry","batching"],"backgroundTag":"duplicate-request-id","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}