keras-team/keras · error · ValueError

The `mask` passed to the `TimeDistributed` layer must be at

Error message

The `mask` passed to the `TimeDistributed` layer must be at least 2D (e.g., `(batch_size, timesteps)`), but it has {len(mask_shape)} dimension(s) with shape {mask_shape}.

What it means

When a mask is passed to TimeDistributed.call, the mask must carry per-(batch, timestep) validity, so it must be at least 2D with shape (batch_size, timesteps). A 0D or 1D mask cannot be aligned with the time axis, so the layer rejects it before checking dimension matches. This typically surfaces when an upstream masking layer (e.g. Embedding(mask_zero=True) or Masking) produced a degenerate mask.

Source

Thrown at keras/src/layers/rnn/time_distributed.py:81

    def compute_output_shape(self, input_shape):
        child_input_shape = self._get_child_input_shape(input_shape)
        child_output_shape = self.layer.compute_output_shape(child_input_shape)
        return (child_output_shape[0], input_shape[1], *child_output_shape[1:])

    def build(self, input_shape):
        child_input_shape = self._get_child_input_shape(input_shape)
        super().build(child_input_shape)

    def call(self, inputs, training=None, mask=None):
        # Validate mask shape using static shape info when available
        if mask is not None:
            mask_shape = mask.shape
            input_shape = inputs.shape

            # Check if mask has at least 2 dimensions (batch and timesteps)
            if len(mask_shape) < 2:
                raise ValueError(
                    "The `mask` passed to the `TimeDistributed` layer must be "
                    "at least 2D (e.g., `(batch_size, timesteps)`), but it has "
                    f"{len(mask_shape)} dimension(s) with shape {mask_shape}."
                )

            # Check batch size and timesteps dimensions match
            batch_mismatch = (
                input_shape[0] is not None
                and mask_shape[0] is not None
                and input_shape[0] != mask_shape[0]
            )
            time_mismatch = (
                input_shape[1] is not None
                and mask_shape[1] is not None
                and input_shape[1] != mask_shape[1]
            )

            if batch_mismatch or time_mismatch:

View on GitHub (pinned to 7a34a03db6)

Solutions

  1. Ensure the mask has shape (batch_size, timesteps) matching the input's first two dims
  2. Fix the upstream layer's compute_mask to not squeeze below 2D
  3. If calling manually, expand the mask: mask = keras.ops.expand_dims(mask, axis=-1) so it becomes (batch, 1) or reshape to (batch, timesteps)

Example fix

# before
out = td_layer(x, mask=mask_1d)  # mask_1d shape (batch,)

# after
mask_2d = keras.ops.expand_dims(mask_1d, axis=-1)  # (batch, 1) timesteps axis
out = td_layer(x, mask=mask_2d)
Defensive patterns

Strategy: validation

Validate before calling

if mask is not None and len(mask.shape) < 2:
    mask = keras.ops.expand_dims(mask, -1)  # ensure at least (batch, timesteps)
out = td_layer(x, mask=mask)

Type guard

def is_valid_td_mask(mask) -> bool:
    return mask is None or len(mask.shape) >= 2

Prevention

When it happens

Trigger: Passing mask with shape (), (batch,), or (batch*timesteps,) to TimeDistributed; a custom upstream layer's compute_mask returning a 1D tensor; manually calling layer(x, mask=flat_mask).

Common situations: A preceding Masking/Embedding(mask_zero=True) layer emitting a squeezed mask; custom layers whose compute_mask calls ops.squeeze; Keras 3 migrations where legacy mask plumbing differed; ragged data converted incorrectly to dense tensors.

Related errors


AI-assisted analysis of keras-team/keras@7a34a03db6 (2026-08-25). Data as JSON: /api/errors/4efdf6007166bde2. Report an issue: GitHub.