google-research/timesfm · error · ValueError

Inputs must be of rank 3 or 4.

Error message

Inputs must be of rank 3 or 4.

What it means

The sinusoid broadcasting logic in the rotary embedding supports only rank-3 (b, n, d) and rank-4 (b, h, n, d) inputs, adjusting position/timescale axes accordingly. Any other rank falls through to this ValueError at forward time.

Source

Thrown at src/timesfm/flax/transformer.py:106

        "The embedding dims of the rotary position embedding"
        "must match the hidden dimension of the inputs."
      )
    half_embedding_dim = self.embedding_dims // 2
    fraction = 2 * jnp.arange(0, half_embedding_dim) / self.embedding_dims
    timescale = (
      self.min_timescale * (self.max_timescale / self.min_timescale) ** fraction
    )
    if position is None:
      seq_length = inputs.shape[1]
      position = jnp.arange(seq_length, dtype=jnp.float32)[None, :]
    if len(inputs.shape) == 4:
      position = position[..., None, None]
      timescale = timescale[None, None, None, :]
    elif len(inputs.shape) == 3:
      position = position[..., None]
      timescale = timescale[None, None, :]
    else:
      raise ValueError("Inputs must be of rank 3 or 4.")
    sinusoid_inp = position / timescale
    sin = jnp.sin(sinusoid_inp)
    cos = jnp.cos(sinusoid_inp)
    first_half, second_half = jnp.split(inputs, 2, axis=-1)
    first_part = first_half * cos - second_half * sin
    second_part = second_half * cos + first_half * sin
    first_part = first_part.astype(None)
    second_part = second_part.astype(None)
    return jnp.concatenate([first_part, second_part], axis=-1)


class PerDimScale(nnx.Module):
  """Per-dimension scaling."""

  __data__ = ("per_dim_scale",)

  def __init__(self, num_dims: int, *, rngs=nnx.Rngs(42)):
    del rngs

View on GitHub (pinned to 331c6d33cb)

Solutions

  1. Add a batch axis: reshape inputs from (n, d) to (1, n, d) before the call.
  2. Ensure the tensor is exactly rank 3 or 4 (batch, [heads,] positions, features) when entering the module.
  3. Check upstream code for unintended squeeze()/reshape() calls that drop or add axes.

Example fix

// before
y = rotary(x)  # x.shape == (n, d) -> ValueError
// after
x = x[None, :, :]  # now rank 3: (1, n, d)
y = rotary(x)
Defensive patterns

Strategy: validation

Validate before calling

if inputs.ndim not in (3, 4):
    raise ValueError(f"expected rank 3 or 4 input, got rank {inputs.ndim}")

Type guard

def is_rank_3_or_4(x) -> bool:
    return x.ndim in (3, 4)

Try / catch

try:
    out = rotary(x)
except ValueError as e:
    if "rank 3 or 4" in str(e):
        while x.ndim < 3:
            x = x[None]
        out = rotary(x)
    else:
        raise

Prevention

When it happens

Trigger: Calling the rotary position embedding __call__ with a 2D tensor (no batch), a 1D vector, or a 5D tensor, e.g. passing a single sequence of shape (n, d) without a batch axis.

Common situations: Debugging with a single example and forgetting the batch dimension, squeezing the batch axis before the rotary layer, or piping in a tensor from another module that adds/removes an axis.

Related errors


AI-assisted analysis of google-research/timesfm@331c6d33cb (2026-08-29). Data as JSON: /api/errors/58958ec9930a9526. Report an issue: GitHub.