The Silent NaN Factory: varlen_attn and the Padding Problem

2026-07-04 · BUG-002 · Gap: REAL FIX / PR #188933

# POST-002 — The Silent NaN Factory: varlen_attn and the Padding Problem

**BUG-002** | **Source**: pytorch/pytorch#176793 | **PR**: #188933 (REAL FIX, pas juste un test)
**Date**: 2026-07-04 | **Detection**: NeuralDBG | **Fix type**: Input validation (ValueError)

---

1. The Bug

**What**: `varlen_attn()` silently produces NaN gradients when query/key tensors are longer than `cu_seqlens[-1]`. Forward pass completes without error. Backward produces NaN.

**Upstream**: [pytorch#176793](https://github.com/pytorch/pytorch/issues/176793) — OPEN.

This is a **silent correctness bug**: extra padding tokens (common in batched variable-length sequences) cause NaN gradients with no error message. Users debug for hours because the forward pass looks completely fine.

2. Reproduction


import torch

TOTAL = 944
cu_seqlens = torch.tensor([0, 144, 432, 944], dtype=torch.int32, device='cuda')
x = torch.randn(TOTAL + 2, 1024, device='cuda', requires_grad=True)
# 2 extra padding tokens — forward OK, backward NaN!
q, k, v = x.chunk(3, dim=-1)

loss = torch.nn.attention.varlen.varlen_attn(
    q, k, v, cu_seqlens, cu_seqlens, 512, 512
).sum()
loss.backward()  # NaN in gradients!

3. Why It Happens

The extra tokens are outside the attention computation (not covered by any sequence in `cu_seqlens`) but still participate in the autograd graph. The forward pass ignores them, but the backward pass tries to compute gradients through them — and fails.

4. NeuralDBG Diagnosis

NeuralDBG traces the NaN gradient back to `varlen_attn`:


gradient_health_transition at qkv.weight: NORMAL → nan_detected
  → optimizer_instability at Adam: diverging
  → training failure

The causal chain pinpoints `qkv.weight` as the source of NaN.

5. The Fix (PR #188933)

Instead of silently producing NaN, we raise a clear `ValueError`:


total_q = cu_seq_q[-1].item()
if query.size(0) > total_q:
    raise ValueError(
        f"query has {query.size(0)} tokens but cu_seq_q[-1] = {total_q}. "
        f"query length must not exceed cu_seq_q[-1] to avoid NaN gradients. "
        f"See https://github.com/pytorch/pytorch/issues/176793."
    )

**This converts a silent NaN corruption into an explicit, actionable error.** The user immediately knows what's wrong and how to fix it.

6. Why This Is Different

Unlike PRs #188053, #188066, #188923 (test-only), this PR changes **core PyTorch behavior** in `torch/nn/attention/varlen.py`. It's a real fix, not just detection.

---

*Detected by [NeuralDBG](https://github.com/LambdaSection/NeuralDBG). See all [post-mortems](index.html).*

Detected by NeuralDBG - causal diagnostic engine for PyTorch training. All post-mortems