The TPU canary ferry (Grug MoE smoke test) crashes at compile time on the first train_step. On this run the crash was deterministic across all 4 task attempts, so max_task_failures was exceeded and the job failed.
The expert grouped-matmul fails to lower on TPU v6e: the megablox GMM pallas_call builds an output BlockSpec((512, 32)) for an output array of shape (524288, 128). Pallas requires the last block dim to be divisible by 128 or equal to the array dim; 32 is neither.
ValueError: The Pallas TPU lowering currently requires that the last two
dimensions of your block shape are divisible by 8 and 128 respectively, or be
equal to the respective dimensions of the overall array. Block spec for outputs
in pallas_call kernel at .../pallas/ops/tpu/megablox/gmm.py:393 has block shape
(Blocked(block_size=512), Blocked(block_size=32)), array shape (524288, 128)
Call path: levanter/grug/_moe/scatter.py:48 (expert MLP projection), then haliax.nn.ragged_dot._ragged_dot_megablox_impl (lib/haliax/src/haliax/nn/ragged_dot.py:93), then jax.experimental.pallas.ops.tpu.megablox.gmm. The output n=128 equals the canary model intermediate_dim.
Reproduce:
- Run the TPU canary ferry
python -m experiments.ferries.canary_ferry on v6e-4 (CANARY_MODEL: hidden_dim=32, intermediate_dim=128, num_experts=32, num_experts_per_token=2, num_layers=4).
- The failure is intermittent across scheduled runs (history below); it reproduces when the megablox GMM lowers fresh instead of loading from the shared JAX compilation cache.
Expected: the megablox GMM lowers with a valid output block (last dim divisible by 128, or equal to n) and the canary trains to the regression gate.
Root-cause status (unresolved discrepancy)
The observed tn=32 does not match the checked-out tiling logic. _megablox_tile_size() at HEAD returns an n-tile of 1024, so _ragged_dot_megablox_impl passes tiling[2] = min(n=128, 1024) = 128, which would produce a valid (512, 128) output block. Static reading of the current code does not explain how tn=32 was emitted. This gap is the crux and needs a kernel owner.
Signals pointing away from a fresh code regression on the commit for this run:
- The prior scheduled canary (2026-08-27 06:30 UTC,
f8972ac) succeeded. The three commits since (PR 8721 external eval/RL runtimes, PR 8717 echo dashboard, PR 8710 IAM grant) touch no JAX, haliax, levanter, or grug code.
ragged_dot.py last changed 2026-08-25 (PR 8610), before two successful runs.
- Canary history alternates pass/fail (Aug 26 pass, Aug 27 06:30 pass, 03:42 and 17:21 fail).
The failing attempt logged a compilation-cache read failure immediately before the crash:
UserWarning: Error reading persistent compilation cache entry for
jit__create_lm_example: RuntimeError: Session is closed
Shared cache: gs://marin-eu-west4/tmp/ttl=30d/compilation-cache. Leading hypothesis: a latent megablox tiling incompatibility for these shapes, normally masked by compilation-cache hits and exposed when the cache read fails and the kernel lowers cold. Not confirmed.
Canary run context:
The TPU canary ferry (Grug MoE smoke test) crashes at compile time on the first
train_step. On this run the crash was deterministic across all 4 task attempts, somax_task_failureswas exceeded and the job failed.The expert grouped-matmul fails to lower on TPU v6e: the megablox GMM
pallas_callbuilds an outputBlockSpec((512, 32))for an output array of shape(524288, 128). Pallas requires the last block dim to be divisible by 128 or equal to the array dim; 32 is neither.Call path:
levanter/grug/_moe/scatter.py:48(expert MLP projection), thenhaliax.nn.ragged_dot._ragged_dot_megablox_impl(lib/haliax/src/haliax/nn/ragged_dot.py:93), thenjax.experimental.pallas.ops.tpu.megablox.gmm. The output n=128 equals the canary model intermediate_dim.Reproduce:
python -m experiments.ferries.canary_ferryonv6e-4(CANARY_MODEL: hidden_dim=32, intermediate_dim=128, num_experts=32, num_experts_per_token=2, num_layers=4).Expected: the megablox GMM lowers with a valid output block (last dim divisible by 128, or equal to n) and the canary trains to the regression gate.
Root-cause status (unresolved discrepancy)
The observed tn=32 does not match the checked-out tiling logic.
_megablox_tile_size()at HEAD returns an n-tile of 1024, so_ragged_dot_megablox_implpassestiling[2] = min(n=128, 1024) = 128, which would produce a valid(512, 128)output block. Static reading of the current code does not explain how tn=32 was emitted. This gap is the crux and needs a kernel owner.Signals pointing away from a fresh code regression on the commit for this run:
f8972ac) succeeded. The three commits since (PR 8721 external eval/RL runtimes, PR 8717 echo dashboard, PR 8710 IAM grant) touch no JAX, haliax, levanter, or grug code.ragged_dot.pylast changed 2026-08-25 (PR 8610), before two successful runs.The failing attempt logged a compilation-cache read failure immediately before the crash:
Shared cache:
gs://marin-eu-west4/tmp/ttl=30d/compilation-cache. Leading hypothesis: a latent megablox tiling incompatibility for these shapes, normally masked by compilation-cache hits and exposed when the cache read fails and the kernel lowers cold. Not confirmed.Canary run context:
/runner/iris-run-job-20260827-172216