{"record":{"id":"83a426c06e222ccd","repo":"xai-org/x-algorithm","slug":"block-sparsity-requires-sparse-block-size-1-n-bl","errorCode":null,"errorMessage":"Block sparsity requires sparse_block_size[1]={n_block_size} to match tile_n.","messagePattern":"Block sparsity requires sparse_block_size\\[1\\]=(.+?) to match tile_n\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"phoenix/xrex/cutedsl/ranker_fa4/block_sparsity.py","lineNumber":557,"sourceCode":"\n\ndef normalize_block_sparse_config(\n    tensors: BlockSparseTensorsTorch,\n    *,\n    batch_size: int,\n    num_head: int,\n    seqlen_q: int,\n    seqlen_k: int,\n    block_size: tuple[int, int],\n    q_stage: int,\n) -> tuple[BlockSparseTensorsTorch, Tuple[Tuple[bool, ...], ...] | None, int]:\n    m_block_size, n_block_size = block_size\n    if tensors.block_size is None:\n        sparse_block_size_q, sparse_block_size_kv = None, n_block_size\n    else:\n        sparse_block_size_q, sparse_block_size_kv = tensors.block_size\n    if sparse_block_size_kv != n_block_size:\n        raise ValueError(\n            f\"Block sparsity requires sparse_block_size[1]={n_block_size} to match tile_n.\"\n        )\n    if tensors.cu_total_m_blocks is not None:\n        base_m_block = q_stage * m_block_size\n        if sparse_block_size_q is not None and sparse_block_size_q != base_m_block:\n            raise ValueError(\n                f\"Varlen block sparsity requires sparse_block_size[0]={base_m_block} \"\n                f\"(= q_stage * tile_m); got {sparse_block_size_q}.\"\n            )\n        total_m_blocks = tensors.mask_block_cnt.shape[-1]\n        total_n_blocks = tensors.mask_block_idx.shape[-1]\n        expected_count_shape = (num_head, total_m_blocks)\n        expected_index_shape = (num_head, total_n_blocks)\n        q_subtile_factor = 1\n    else:\n        expected_count_shape, expected_index_shape, q_subtile_factor = (\n            infer_block_sparse_expected_shapes(\n                tensors,","sourceCodeStart":539,"sourceCodeEnd":575,"githubUrl":"https://github.com/xai-org/x-algorithm/blob/24c60942c5c5fdad3a6addffb4c6e6d2f228f04f/phoenix/xrex/cutedsl/ranker_fa4/block_sparsity.py#L539-L575","documentation":"In the forward normalize_block_sparse_config, the KV side of the sparse block size must equal tile_n (the kernel's N tile). block_size defaults to (None, n_block_size) when tensors.block_size is None, so this fires when an explicit block_size[1] differs from tile_n.","triggerScenarios":"Setting BlockSparseTensorsTorch.block_size = (q, kv) with kv != the kernel's tile_n (e.g. 256 while the FA4 config uses tile_n=128), or building a BlockMask with BLOCK_SIZE kv not matching the ranker tile config.","commonSituations":"Reusing a FlexAttention BlockMask whose KV BLOCK_SIZE doesn't match this kernel's tile_n; changing the kernel tile config without rebuilding masks.","solutions":["Set sparse_block_size[1] (block_size[1] / BlockMask KV BLOCK_SIZE) equal to tile_n, or leave tensors.block_size None to default correctly","Rebuild the block mask with the kernel's tile_n","Check the ranker FA4 config's tile_n and align the mask generator"],"exampleFix":"# before\ntensors = BlockSparseTensorsTorch(..., block_size=(128, 256))  # tile_n=128\n\n# after\ntensors = BlockSparseTensorsTorch(..., block_size=(128, 128))\n# or block_size=None to use the default n_block_size","handlingStrategy":"validation","validationCode":"assert tensors.block_size is None or tensors.block_size[1] == tile_n, \\\n    (tensors.block_size, tile_n)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer block_size=None to use kernel defaults","Keep tile_n in a single shared config"],"tags":["block-sparsity","block-size","tile-config"],"backgroundTag":"configuration-mismatch","analyzedSha":"24c60942c5c5fdad3a6addffb4c6e6d2f228f04f","analyzedAt":"2026-08-28T11:40:14.686Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}