{"record":{"id":"5477bcf75f12ee19","repo":"sgl-project/sglang","slug":"speculative-algorithm-upper-already-registered","errorCode":null,"errorMessage":"Speculative algorithm '{upper}' already registered.","messagePattern":"Speculative algorithm '(.+?)' already registered\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/speculative/spec_registry.py","lineNumber":243,"sourceCode":"def register_algorithm(\n    name: str,\n    *,\n    supports_overlap: bool = False,\n    validate_server_args: Optional[ServerArgsValidator] = None,\n    spec_class: Type[CustomSpecAlgo] = CustomSpecAlgo,\n) -> Callable[[WorkerFactory], WorkerFactory]:\n    \"\"\"Return a decorator that registers a plugin algorithm under ``name``.\n\n    Pass a ``spec_class`` subclass of ``CustomSpecAlgo`` to override any\n    ``is_*()`` / ``supports_*()`` / ``create_worker`` method.\n    \"\"\"\n    upper = name.upper()\n    if upper in _reserved_names():\n        raise ValueError(\n            f\"'{upper}' is a reserved speculative algorithm name; cannot be re-registered.\"\n        )\n    if upper in _REGISTRY:\n        raise ValueError(f\"Speculative algorithm '{upper}' already registered.\")\n    _assert_custom_spec_algo_conforms(spec_class)\n\n    def decorator(factory: WorkerFactory) -> WorkerFactory:\n        _REGISTRY[upper] = spec_class(\n            name=upper,\n            factory=factory,\n            supports_overlap=supports_overlap,\n            validate_server_args=validate_server_args,\n        )\n        return factory\n\n    return decorator\n\n\ndef get_spec(name: Optional[str]) -> Optional[CustomSpecAlgo]:\n    \"\"\"Return the registered spec for ``name``, or ``None`` for builtin /\n    unknown names.\"\"\"\n    if name is None:","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/speculative/spec_registry.py#L225-L261","documentation":"The speculative algorithm registry refuses double registration: if the uppercased name is already a key in _REGISTRY, register_algorithm raises ValueError. This usually means the registering module was imported twice or the register call runs at import time in a re-imported module.","triggerScenarios":"Importing the plugin module twice (e.g. via different sys.paths or both an entry point and an explicit import), or calling register_algorithm twice with the same name in tests that don't clear _REGISTRY.","commonSituations":"Test suites re-registering algorithms without resetting the registry; duplicate module import under 'sglang.srt.x' and 'srt.x' style paths.","solutions":["Guard re-registration: delete _REGISTRY[NAME] in test teardown before re-importing","Make the plugin idempotent: only register if name not already in the registry","Fix duplicate imports (normalize import paths, avoid re-executing the entry point)"],"exampleFix":"# before\n@register_algorithm('MYALGO')  # module imported twice -> raises\n# after\nif 'MYALGO' not in _REGISTRY:\n    @register_algorithm('MYALGO')\n    def factory(...): ...","handlingStrategy":"try-catch","validationCode":"from sglang.srt.speculative.spec_registry import _REGISTRY\nif 'MYALGO' in _REGISTRY:\n    del _REGISTRY['MYALGO']  # e.g. in test teardown before re-import","typeGuard":null,"tryCatchPattern":"try:\n    register_algorithm('MYALGO')(factory)\nexcept ValueError as e:\n    if 'already registered' not in str(e):\n        raise  # idempotent re-registration is fine","preventionTips":["Make registration idempotent (guard on registry contents)","Clear the registry in test setUp/tearDown when re-importing plugin modules"],"tags":["speculative-decoding","plugin-api","duplicate-registration"],"backgroundTag":"duplicate-registration","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}