{"record":{"id":"0edb70db00b9db53","repo":"sgl-project/sglang","slug":"n-must-be-a-positive-power-of-2-got-n","errorCode":null,"errorMessage":"n must be a positive power of 2, got {n}","messagePattern":"n must be a positive power of 2, got (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/hardware_backend/npu/attention/ascend_dsv4_backend.py","lineNumber":40,"sourceCode":"from sglang.srt.runtime_context import get_parallel\n\nif TYPE_CHECKING:\n    from sglang.srt.layers.radix_attention import RadixAttention\n    from sglang.srt.model_executor.forward_batch_info import ForwardBatch\n    from sglang.srt.model_executor.model_runner import ModelRunner\n\nlogger = logging.getLogger(__name__)\n\n\ndef _walsh_hadamard_matrix(n: int, dtype: torch.dtype, device) -> torch.Tensor:\n    # n**-0.5 norm is baked in via the sqrt(2) division per doubling; _apply_hadamard is a plain matmul\n    cache = _walsh_hadamard_matrix._cache\n    key = (n, str(device))\n    cached = cache.get(key)\n    if cached is not None:\n        return cached\n    if not ((n & (n - 1) == 0) and (n > 0)):\n        raise ValueError(f\"n must be a positive power of 2, got {n}\")\n    had = torch.ones(1, 1, dtype=torch.bfloat16, device=device)\n    while had.shape[0] != n:\n        had = torch.cat((torch.cat([had, had], 1), torch.cat([had, -had], 1)), 0)\n        had /= math.sqrt(2)\n    had = had.contiguous()\n    cache[key] = had\n    return had\n\n\n_walsh_hadamard_matrix._cache = {}\n\n\ndef _apply_hadamard(inp: torch.Tensor, hadamard_matrix: torch.Tensor) -> torch.Tensor:\n    init_shape = inp.shape\n    flat = inp.view(-1, hadamard_matrix.shape[0])\n    return flat.matmul(hadamard_matrix).view(init_shape).to(torch.bfloat16)\n\n","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/hardware_backend/npu/attention/ascend_dsv4_backend.py#L22-L58","documentation":"_walsh_hadamard_matrix builds a cached Walsh–Hadamard transform matrix used by the Ascend DSV4 indexer; the fast iterative construction only works for sizes that are positive powers of two, so any other n is rejected before construction.","triggerScenarios":"Calling _walsh_hadamard_matrix(n) with n not a positive power of two — e.g. n=3, n=0, negative n, or a non-integer that slips through — typically from _ensure_compressor_hadamard/_ensure_npu_c4_indexer deriving n from a head dim or compressor ratio that isn't a power of two.","commonSituations":"Configuring the DSV4 NPU indexer with a custom head_dim/compressor ratio like 3/4 or 6 that yields non-power-of-2 sizes; model configs with unusual qk/down-proj dims; unit tests probing invalid shapes.","solutions":["Ensure the derived size (head dim / compressor ratio) is a power of two, e.g. 64/128/256","Check the model config for the DSV4 indexer (head dims, compressor settings) against supported values","If you control the caller, validate and fail early with a clear config error before launching","Use the standard DeepSeek v4 config, which produces power-of-2 sizes"],"exampleFix":"# before\nH = _walsh_hadamard_matrix(96)  # ValueError\n# after\nH = _walsh_hadamard_matrix(128)","handlingStrategy":"validation","validationCode":"def is_pow2(n: int) -> bool:\n    return isinstance(n, int) and n > 0 and (n & (n - 1)) == 0\nassert is_pow2(n), f\"n={n} is not a positive power of two\"","typeGuard":"def is_valid_hadamard_size(n) -> bool:\n    return isinstance(n, int) and n > 0 and (n & (n - 1)) == 0","tryCatchPattern":"try:\n    had = _walsh_hadamard_matrix(n)\nexcept ValueError as e:\n    n2 = 1 << (n - 1).bit_length()  # round up to next power of two\n    had = _walsh_hadamard_matrix(n2)","preventionTips":["Validate head dims / compressor ratios are powers of two before building the indexer","Use stock DSV4 model configs","Wrap indexer construction with a config linter at startup"],"tags":["ascend","dsv4","hadamard","validation","npu","sglang"],"backgroundTag":"invalid-argument-value","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}