{"record":{"id":"5bf5940e5aca8825","repo":"PaddlePaddle/PaddleOCR","slug":"this-attention-mask-converter-is-causal-make-sure-5bf594","errorCode":null,"errorMessage":"This attention mask converter is causal. Make sure to pass `key_value_length` to correctly create a causal mask.","messagePattern":"This attention mask converter is causal\\. Make sure to pass `key_value_length` to correctly create a causal mask\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"ppocr/modeling/heads/rec_unimernet_head.py","lineNumber":345,"sourceCode":"        )\n        expanded_4d_mask = expanded_attn_mask\n\n        return expanded_4d_mask\n\n    def to_4d(\n        self,\n        attention_mask_2d,\n        query_length,\n        dtype,\n        key_value_length,\n        is_export=False,\n    ):\n\n        input_shape = (attention_mask_2d.shape[0], query_length)\n        causal_4d_mask = None\n        if (input_shape[-1] > 1 or self.sliding_window is not None) and self.is_causal:\n            if key_value_length is None:\n                raise ValueError(\n                    \"This attention mask converter is causal. Make sure to pass `key_value_length` to correctly create a causal mask.\"\n                )\n\n            past_key_values_length = key_value_length - query_length\n\n            causal_4d_mask = self._make_causal_mask(\n                input_shape,\n                dtype,\n                past_key_values_length=past_key_values_length,\n                sliding_window=self.sliding_window,\n                is_export=is_export,\n            )\n        elif self.sliding_window is not None:\n            raise NotImplementedError(\n                \"Sliding window is currently only implemented for causal masking\"\n            )\n\n        expanded_attn_mask = self._expand_mask(","sourceCodeStart":327,"sourceCodeEnd":363,"githubUrl":"https://github.com/PaddlePaddle/PaddleOCR/blob/2661c7c0ef5c613e8f93c6e93b2e052399f0f854/ppocr/modeling/heads/rec_unimernet_head.py#L327-L363","documentation":"The UniMERNet causal mask converter must compute past_key_values_length = key_value_length - query_length whenever the sequence is longer than one token (or a sliding window is configured). Without key_value_length that is impossible, so it raises this ValueError.","triggerScenarios":"Calling to_4d on the converter without key_value_length while query_length > 1 or sliding_window is set — typically in custom decode loops, step-wise inference harnesses, or refactored forward code that dropped the argument.","commonSituations":"Writing a custom generation loop for UniMERNet and only passing (mask, seq_len, dtype); mixing cached KV inference with fresh mask creation; porting mask code between the PP-FormulaNet and UniMERNet heads where signatures differ slightly.","solutions":["Always pass key_value_length: past_key_values_length + query_length (from cache shape when present, else query_length)","Reuse the head's own forward logic (which computes it from past_key_values) instead of reimplementing mask creation","Add a unit test that decodes 2+ steps to catch the missing argument early"],"exampleFix":"# before\nmask = converter.to_4d(attn_mask, L, dtype=dtype)\n# after\nkv = past_k.shape[2] + L if past_k is not None else L\nmask = converter.to_4d(attn_mask, L, dtype=dtype, key_value_length=kv)","handlingStrategy":"validation","validationCode":"def kv_length(past_key_values, q_len):\n    if past_key_values is None:\n        return q_len\n    return past_key_values[0][0].shape[2] + q_len\n# converter.to_4d(mask, q_len, key_value_length=kv_length(past, q_len), dtype=dtype)","typeGuard":"null","tryCatchPattern":"try:\n    mask = converter.to_4d(mask, q_len, dtype=dtype)\nexcept ValueError as e:\n    if 'key_value_length' in str(e):\n        mask = converter.to_4d(mask, q_len, key_value_length=q_len, dtype=dtype)\n    else:\n        raise","preventionTips":["Pass key_value_length on every multi-token decode step","Reuse the head's forward mask logic instead of reimplementing it","Test custom decode loops beyond a single step"],"tags":["attention-mask","decoding","unimernet","api-misuse"],"backgroundTag":null,"analyzedSha":"2661c7c0ef5c613e8f93c6e93b2e052399f0f854","analyzedAt":"2026-08-14T20:17:30.180Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}