PaddlePaddle/PaddleOCR · error · ValueError

This attention mask converter is causal. Make sure to pass `

Error message

This attention mask converter is causal. Make sure to pass `key_value_length` to correctly create a causal mask.

What it means

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.

Source

Thrown at ppocr/modeling/heads/rec_unimernet_head.py:345

        )
        expanded_4d_mask = expanded_attn_mask

        return expanded_4d_mask

    def to_4d(
        self,
        attention_mask_2d,
        query_length,
        dtype,
        key_value_length,
        is_export=False,
    ):

        input_shape = (attention_mask_2d.shape[0], query_length)
        causal_4d_mask = None
        if (input_shape[-1] > 1 or self.sliding_window is not None) and self.is_causal:
            if key_value_length is None:
                raise ValueError(
                    "This attention mask converter is causal. Make sure to pass `key_value_length` to correctly create a causal mask."
                )

            past_key_values_length = key_value_length - query_length

            causal_4d_mask = self._make_causal_mask(
                input_shape,
                dtype,
                past_key_values_length=past_key_values_length,
                sliding_window=self.sliding_window,
                is_export=is_export,
            )
        elif self.sliding_window is not None:
            raise NotImplementedError(
                "Sliding window is currently only implemented for causal masking"
            )

        expanded_attn_mask = self._expand_mask(

View on GitHub (pinned to 2661c7c0ef)

Solutions

  1. Always pass key_value_length: past_key_values_length + query_length (from cache shape when present, else query_length)
  2. Reuse the head's own forward logic (which computes it from past_key_values) instead of reimplementing mask creation
  3. Add a unit test that decodes 2+ steps to catch the missing argument early

Example fix

# before
mask = converter.to_4d(attn_mask, L, dtype=dtype)
# after
kv = past_k.shape[2] + L if past_k is not None else L
mask = converter.to_4d(attn_mask, L, dtype=dtype, key_value_length=kv)
Defensive patterns

Strategy: validation

Validate before calling

def kv_length(past_key_values, q_len):
    if past_key_values is None:
        return q_len
    return past_key_values[0][0].shape[2] + q_len
# converter.to_4d(mask, q_len, key_value_length=kv_length(past, q_len), dtype=dtype)

Type guard

null

Try / catch

try:
    mask = converter.to_4d(mask, q_len, dtype=dtype)
except ValueError as e:
    if 'key_value_length' in str(e):
        mask = converter.to_4d(mask, q_len, key_value_length=q_len, dtype=dtype)
    else:
        raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of PaddlePaddle/PaddleOCR@2661c7c0ef (2026-08-14). Data as JSON: /api/errors/5bf5940e5aca8825. Report an issue: GitHub.