{"record":{"id":"dd96afee5a16e92b","repo":"sgl-project/sglang","slug":"external-corpus-corpus-id-already-exists-remo","errorCode":null,"errorMessage":"External corpus '{corpus_id}' already exists. Remove it before adding a new corpus with the same id.","messagePattern":"External corpus '(.+?)' already exists\\. Remove it before adding a new corpus with the same id\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/speculative/cpp_ngram/ngram_corpus.py","lineNumber":66,"sourceCode":"            self._next_state_id += 1\n            self._req_id_to_state_id[req_id] = sid\n        return sid\n\n    def batch_put(self, batch_tokens: List[List[int]]):\n        self._obj.insert(batch_tokens)\n\n    def synchronize(self):\n        self._obj.synchronize()  # type: ignore\n\n    @property\n    def remaining_token_budget(self) -> int:\n        return self.external_corpus_max_tokens - self._total_loaded_tokens\n\n    def load_external_corpus_named(\n        self, corpus_id: str, chunks: Iterable[Sequence[int]]\n    ) -> int:\n        if corpus_id in self._corpus_token_counts:\n            raise ValueError(\n                f\"External corpus '{corpus_id}' already exists. Remove it before \"\n                f\"adding a new corpus with the same id.\"\n            )\n        # Note(kpham-sgl): remaining_token_budget is stale (e.g if there are removes\n        # during the load), which makes the budget more conservative than it should be.\n        # This is acceptable because otherwise load_external_corpus_named would need to check the budget after each chunk,\n        # which would be inefficient.\n        _, loaded_token_count = self._obj.load_external_corpus_named(\n            corpus_id, chunks, self.remaining_token_budget\n        )\n        return loaded_token_count\n\n    # Commit corpus bookkeeping after successful load. Call only at background thread join.\n    # (or after synchronous load_external_corpus_named returns)\n    def commit_external_corpus_load(\n        self, corpus_id: str, loaded_token_count: int\n    ) -> None:\n        self._corpus_token_counts[corpus_id] = loaded_token_count","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/speculative/cpp_ngram/ngram_corpus.py#L48-L84","documentation":"Ngram_corpus tracks loaded external corpora by corpus_id in _corpus_token_counts. load_external_corpus_named refuses to overwrite: re-loading an id that already exists raises this ValueError, telling the caller to remove the old corpus first.","triggerScenarios":"Calling load_external_corpus_named (or add_external_corpus) twice with the same corpus_id without an intervening remove_external_corpus(corpus_id).","commonSituations":"Re-adding a corpus after editing its file (e.g. hot-reload of knowledge), retry logic that re-sends the same id, or duplicate ids from a config list.","solutions":["Remove the existing corpus first: remove_external_corpus(corpus_id), then reload","Or use a new unique corpus_id for the updated corpus"],"exampleFix":"# before\nmanager.add_external_corpus(\"docs\", chunks)  # second time -> ValueError\n# after\nif \"docs\" in manager.list_external_corpora():\n    manager.remove_external_corpus(\"docs\")\nmanager.add_external_corpus(\"docs\", chunks)","handlingStrategy":"validation","validationCode":"if corpus_id in manager.list_external_corpora():  # or equivalent membership check\n    manager.remove_external_corpus(corpus_id)\nmanager.load_external_corpus_named(corpus_id, chunks)","typeGuard":null,"tryCatchPattern":"try:\n    manager.load_external_corpus_named(cid, chunks)\nexcept ValueError as e:\n    if \"already exists\" in str(e):\n        manager.remove_external_corpus(cid)\n        manager.load_external_corpus_named(cid, chunks)\n    else:\n        raise","preventionTips":["Make add operations idempotent: remove-then-add wrapped in a helper","Use versioned corpus ids (docs-v2) when updating content"],"tags":["sglang","ngram","duplicate-key","idempotency"],"backgroundTag":"duplicate-resource-id","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}