{"record":{"id":"07c099ab776de8ed","repo":"sgl-project/sglang","slug":"walk-radix-cache-for-canary-does-not-support-type","errorCode":null,"errorMessage":"walk_radix_cache_for_canary does not support {type(radix_cache).__name__}","messagePattern":"walk_radix_cache_for_canary does not support (.+?)","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/kv_canary/radix_cache_walker.py","lineNumber":139,"sourceCode":"def _node_slots_for_canary(*, node: TreeNode) -> list[int]:\n    value: Any = node.value\n    if isinstance(value, torch.Tensor):\n        return [int(s) for s in value.tolist()]\n    return []\n\n\ndef _node_is_unlocked_for_canary(\n    *,\n    node: TreeNode,\n    radix_cache: BasePrefixCache,\n) -> bool:\n    if type(radix_cache) is RadixCache:\n        return node.lock_ref == 0\n\n    if type(radix_cache) is SWARadixCache:\n        return node.full_lock_ref == 0\n\n    raise NotImplementedError(\n        f\"walk_radix_cache_for_canary does not support {type(radix_cache).__name__}\"\n    )\n\n\ndef _node_is_swa_resident_for_canary(\n    *,\n    node: TreeNode,\n    radix_cache: BasePrefixCache,\n) -> bool:\n    if type(radix_cache) is SWARadixCache:\n        return not node.swa_tombstone\n\n    return True\n","sourceCodeStart":121,"sourceCodeEnd":153,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/kv_canary/radix_cache_walker.py#L121-L153","documentation":"The internal lock-state helper _node_is_unlocked_for_canary reads node.lock_ref for RadixCache and node.full_lock_ref for SWARadixCache; any other exact cache type is unsupported and raises NotImplementedError. This guards the canary sweep from selecting locked (in-use) nodes.","triggerScenarios":"A radix cache whose exact type is neither RadixCache nor SWARadixCache reaching _walk_radix_subtree, typically because the public walker's dispatch (line 38) allowed a subclass or the walker was called directly in tests with a custom cache.","commonSituations":"Subclassing RadixCache with a different lock accounting field; mocked cache objects; new cache variants where the canary lock predicate is undefined.","solutions":["Use one of the supported concrete cache types when running canary sweeps","For a new cache type, add a branch to _node_is_unlocked_for_canary defining its unlocked predicate","Audit callers of walk_radix_cache_for_canary (e.g. build_verify_plan_radix_sweep) to confirm they pass a supported cache"],"exampleFix":"// before\nunlocked = _node_is_unlocked_for_canary(radix_cache=my_subclass, node=n)\n# after\nunlocked = (n.lock_ref == 0) if isinstance_cache_supported else extend_walker_for(my_subclass)","handlingStrategy":"type-guard","validationCode":"from sglang.srt.mem_cache.radix_cache import RadixCache, SWARadixCache\nif type(radix_cache) not in (RadixCache, SWARadixCache):\n    raise TypeError('unsupported cache for canary lock check')","typeGuard":"def unlocked(cache, node) -> bool:\n    if type(cache) is RadixCache:\n        return node.lock_ref == 0\n    if type(cache) is SWARadixCache:\n        return node.full_lock_ref == 0\n    raise NotImplementedError(type(cache).__name__)","tryCatchPattern":null,"preventionTips":["Route canary sweeps only through walk_radix_cache_for_canary with supported types","Don't subclass RadixCache with different lock fields and reuse canary tooling"],"tags":["kv-canary","radix-cache","notimplementederror","locking"],"backgroundTag":"unsupported-type-dispatch","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}