Inductor fails to compile cumsum on a 0-dim constant tensor with tuple index out of range
Compilation aborts on a graph containing a cumulative sum over a scalar constant. A post-graph optimisation recognises the pattern, asks the tensor for the length of the dimension being summed, and a scalar has no dimensions to ask about, so indexing its empty shape raises before any code is generated.
An optimisation asks a scalar for the size of a dimension it does not have. Give the constant an explicit dimension, or drop the cumulative sum over a scalar, which is the identity anyway.
What this failure is
A compile-time failure in which a post-graph optimisation for cumulative sum reads a dimension length from the shape of a 0-dimensional constant tensor, whose shape tuple is empty, raising an index error before code generation.
Why it happens (the mechanism)
Pattern-based rewrites match on operation and operands and then assume the shapes they usually see. A cumulative sum is almost always applied to something with at least one dimension, so reading the length of that dimension is a safe-looking step. A scalar constant satisfies the match and violates the assumption, and the guard for the degenerate case was never written because the degenerate case is not useful enough for anyone to have tried it.
What you'll observe
- The same function runs correctly without compilation, so the model is not wrong
- The error is an index error inside the compiler, which says nothing about which operation caused it
- It depends on the tensor being a compile-time constant, so an identical shape produced at runtime does not trigger it
- A scalar cumulative sum looks pointless and is usually incidental to a larger expression nobody wrote deliberately
Common symptoms and what they mean
| Symptom | Why it happens |
|---|---|
| InductorError: IndexError: tuple index out of range raised at compile time | The optimisation exists because a cumulative sum along a dimension of known length can often be replaced with something cheaper. To do that it needs the length, which it reads by indexing the shape tuple with the dimension number. A scalar's shape tuple is empty, so any index into it is out of range. |
| The traceback passing through a post-graph pattern replacement for cumulative sum and a line computing a dimension size from a shape | The pattern only fires for a constant because the rewrite needs the shape at compile time. A tensor of the same rank produced at runtime keeps its size unknown, the precondition fails, and the optimisation declines to apply — which is why an apparently identical program compiles. |
| A suggestion to set a verbose environment variable for the internal stack trace | The rewrite is an optimisation, not a requirement. Nothing about generating code for this graph needs it, which is why the failure feels arbitrary: the compiler is stopping in a step whose entire purpose is to make the result faster. |
| The same code compiling successfully with the graph-capture-only backends and failing only with the default one | The optimisation exists because a cumulative sum along a dimension of known length can often be replaced with something cheaper. To do that it needs the length, which it reads by indexing the shape tuple with the dimension number. A scalar's shape tuple is empty, so any index into it is out of range. |
Which systems are affected
- Compiled graphs containing a cumulative sum over a tensor built from a literal, such as a scalar constant
- The post-graph optimisation stage, which rewrites recognised patterns after the graph is captured and before code generation
- Code where a scalar reaches an operation expecting at least one dimension through broadcasting or a generic helper
- Model code generated or templated rather than written by hand, where a degenerate shape is easy to produce unnoticed
How to confirm this is the problem
Apply the following checklist to a small reproduction: each box below is a positive signal that you are looking at this exact failure rather than a sibling in the same taxonomy.
- ✓Compile with a graph-capture-only backend. Succeeding there while the default backend fails places the fault in code generation rather than in tracing.
- ✓Reduce the function to a cumulative sum over a single scalar constant. Reproducing on that alone identifies the pattern precisely.
- ✓Add an explicit dimension to the constant and recompile. Success confirms the empty shape tuple as the cause.
Example training logs (fingerprint)
torch._inductor.exc.InductorError: IndexError: tuple index out of range
File ".../torch/_inductor/fx_passes/post_grad.py", in pointless_cumsum_replacement
dim_size = shape[dim]
File ".../torch/_inductor/compile_fx.py", in _compile_fx_inner
Set TORCHDYNAMO_VERBOSE=1 for the internal stack traceTimestamps and exact values vary across runs, but the pattern. An info-level start, an early WARN, an ERROR carrying the symptom. Is the actual fingerprint you should alert on. The Denpex platform flags this combination automatically.
Root cause, fix & prevention, signed in
Sign up free to see why this failure really happens, the exact remediation steps, and the production-grade prevention pattern. You also get 3 free full diagnoses for your own training logs.
Sign up free. Unlock the full analysisNo credit card · 3 free diagnoses · Instant access
Why the recommended fix works
Adding a dimension makes the shape tuple non-empty, so the length is readable and the rewrite proceeds normally. Removing the operation avoids the pattern entirely. Computing the constant at runtime leaves its size unknown, and the rewrite requires a compile-time size, so it declines to fire. Each removes the precondition rather than working around the symptom.
Code examples
// Typical pattern:
import torch.optim as optim
optimizer = optim.AdamW(model.parameters(), lr=3e-4)
scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=num_training_steps)
for step in range(num_training_steps):
optimizer.zero_grad()
loss = model(batch)
loss.backward()
optimizer.step()
scheduler.step()Adapt the snippet to your framework. The same pattern holds for PyTorch Lightning, Hugging Face Trainer, DeepSpeed, Megatron-LM, and vLLM training wrappers. Where the wrapper exposes a config flag (for examplelr_scheduler_type in Trainer), prefer the flag over the imperative API to keep the schedule declarative and reproducible.
Best practices by model family
| Model / Stack | Recommendation | Notes |
|---|---|---|
| Scalar constant reaches cumsum | Add an explicit dimension | Values unchanged; shape tuple gains an entry. |
| Operation is incidental | Remove it | Cumulative sum over a scalar is the identity. |
| Diagnosing | Try a capture-only backend | Separates tracing from code generation in one run. |
| Cannot change the model | Exclude the region from compilation | Keeps the rest of the model compiled. |
With the fix vs without the fix
| Dimension | With the fix | Without the fix |
|---|---|---|
| Why eager works | No pattern rewriting happens | Read as a model correctness problem |
| Why a constant specifically | The rewrite needs a compile-time size | Expected to depend on rank alone |
| What the failing step does | An optimisation, not a requirement | Assumed necessary for code generation |
Real engineering notes
“The instructive part is the ablation in the upstream report: the graph-capture backends compile it and only the code-generating one fails. That single check separates a tracing problem from a code-generation problem, and it takes one line. Make it the first thing you do with any compiler error whose traceback lands in framework internals — it halves the search before you have read a single frame properly.”
Visual fingerprint
torch.tensor([5.0]) shape (1,) -> shape[0] = 1 rewrite proceeds
torch.tensor(5.0) shape () -> shape[0] = ??? IndexError
torch.rand(()) shape () -> size unknown at compile time
precondition fails, rewrite skippedRoot cause, fix & prevention
Frequently asked questions
Twelve targeted questions that engineers and on-call staff most commonly ask about this failure.
Is my model wrong?
Why does a runtime-produced scalar not fail?
Do I lose performance by adding a dimension?
How do I tell tracing from code generation?
Don't just read the fix, diagnose your run
The encyclopedia tells you what went wrong. Denpex tells you what went wrong in YOUR training run. With your logs, your config, and your stack.