PaddlePaddle/PaddleOCR · error · ValueError
Incorrect 4D attention_mask shape: {tuple(attention_mask.sha
Error message
Incorrect 4D attention_mask shape: {tuple(attention_mask.shape)}; expected: {expected_shape}. What it means
The decoder accepts a user-supplied 4D attention mask but validates its shape strictly: it must be exactly (batch_size, 1, query_len, key_value_length). A mask of any other rank-4 shape (wrong batch dim, extra heads, swapped q/kv axes, or stale kv length) raises this ValueError.
Source
Thrown at ppocr/modeling/heads/rec_ppformulanet_head.py:335
)
key_value_length = input_shape[-1] + past_key_values_length
# 4d mask is passed through the layers
if attention_mask is not None and len(attention_mask.shape) == 2:
attention_mask = attn_mask_converter.to_4d(
attention_mask,
input_shape[-1],
key_value_length=key_value_length,
dtype=inputs_embeds.dtype,
use_parallel=use_parallel,
parallel_step=parallel_step,
is_export=is_export,
)
elif attention_mask is not None and len(attention_mask.shape) == 4:
expected_shape = (input_shape[0], 1, input_shape[1], key_value_length)
if tuple(attention_mask.shape) != expected_shape:
raise ValueError(
f"Incorrect 4D attention_mask shape: {tuple(attention_mask.shape)}; expected: {expected_shape}."
)
else:
# if the 4D mask has correct shape - invert it and fill with negative infinity
inverted_mask = 1.0 - attention_mask
attention_mask = inverted_mask.masked_fill_(
inverted_mask.to(paddle.bool), paddle.finfo(inputs_embeds.dtype).min
)
else:
attention_mask = attn_mask_converter.to_causal_4d(
input_shape[0],
input_shape[-1],
key_value_length,
dtype=inputs_embeds.dtype,
)
return attention_mask
View on GitHub (pinned to 2661c7c0ef)
Solutions
- Build the 4D mask with exactly (batch, 1, q_len, kv_len); prefer passing a 2D (batch, seq) padding mask and letting to_4d handle expansion
- Inside generation loops, rebuild or slice the mask each step so the last dim tracks the growing kv length
- Check attention_mask.shape[0] equals input batch and shape[2] equals current query length before the call
Example fix
# before attn_mask = my_mask # shape (B, num_heads, L, L) # after - pass 2D and let the model expand attn_mask = padding_mask # shape (B, L) of 0/1
Defensive patterns
Strategy: type-guard
Validate before calling
def check_4d_mask(mask, batch, q_len, kv_len):
expected = (batch, 1, q_len, kv_len)
if mask is not None and len(mask.shape) == 4 and tuple(mask.shape) != expected:
raise ValueError(f'mask {tuple(mask.shape)} != expected {expected}; pass a 2D (B, L) mask instead') Type guard
def is_valid_4d_mask(mask, batch, q_len, kv_len) -> bool:
return mask is None or len(mask.shape) != 4 or tuple(mask.shape) == (batch, 1, q_len, kv_len) Try / catch
try:
out = decoder(attention_mask=mask, ...)
except ValueError as e:
if 'Incorrect 4D attention_mask shape' in str(e):
out = decoder(attention_mask=mask_2d, ...) # fall back to 2D
else:
raise Prevention
- Prefer 2D padding masks; let the model build the 4D form
- In generation loops, rebuild the mask every step as kv length grows
- Assert mask.shape == (B, 1, q, kv) right before the decoder call
When it happens
Trigger: Passing attention_mask with shape (B, H, L, L) with H != 1, (B, 1, kv_len, q_len) transposed, or a mask built for a previous step whose kv length no longer matches during cached/parallel decoding.
Common situations: Feeding a multi-head mask from another HF-style model into this decoder; precomputing masks once outside a generation loop while key_value_length grows each step; batching inputs of mixed lengths with a manually tiled mask.
Related errors
- Make sure that when passing `sliding_window` that its value
- This attention mask converter is causal. Make sure to pass `
- Sliding window is currently only implemented for causal mask
- The `{mask_name}` should be specified for {len(self.layers)}
- You cannot specify both decoder_input_ids and decoder_inputs
AI-assisted analysis of PaddlePaddle/PaddleOCR@2661c7c0ef (2026-08-14).
Data as JSON: /api/errors/436962dcbafd3728.
Report an issue: GitHub.