{"record":{"id":"a6a75afef3c7c341","repo":"keras-team/keras","slug":"the-mask-passed-to-the-timedistributed-layer-h","errorCode":null,"errorMessage":"The `mask` passed to the `TimeDistributed` layer has a shape {mask_shape} that is incompatible with the input shape {input_shape}. The first two dimensions of the mask (batch size and timesteps) must match the input's first two dimensions. Expected mask shape prefix: ({input_shape[0]}, {input_shape[1]}).","messagePattern":"The `mask` passed to the `TimeDistributed` layer has a shape (.+?) that is incompatible with the input shape (.+?)\\. The first two dimensions of the mask \\(batch size and timesteps\\) must match the input's first two dimensions\\. Expected mask shape prefix: \\((.+?), (.+?)\\)\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"keras/src/layers/rnn/time_distributed.py","lineNumber":100,"sourceCode":"                    \"The `mask` passed to the `TimeDistributed` layer must be \"\n                    \"at least 2D (e.g., `(batch_size, timesteps)`), but it has \"\n                    f\"{len(mask_shape)} dimension(s) with shape {mask_shape}.\"\n                )\n\n            # Check batch size and timesteps dimensions match\n            batch_mismatch = (\n                input_shape[0] is not None\n                and mask_shape[0] is not None\n                and input_shape[0] != mask_shape[0]\n            )\n            time_mismatch = (\n                input_shape[1] is not None\n                and mask_shape[1] is not None\n                and input_shape[1] != mask_shape[1]\n            )\n\n            if batch_mismatch or time_mismatch:\n                raise ValueError(\n                    \"The `mask` passed to the `TimeDistributed` layer has a \"\n                    f\"shape {mask_shape} that is incompatible with the input \"\n                    f\"shape {input_shape}. The first two dimensions of the \"\n                    \"mask (batch size and timesteps) must match the input's \"\n                    \"first two dimensions. Expected mask shape prefix: \"\n                    f\"({input_shape[0]}, {input_shape[1]}).\"\n                )\n\n        input_shape = ops.shape(inputs)\n\n        def time_distributed_transpose(data):\n            \"\"\"Swaps the timestep and batch dimensions of a tensor.\"\"\"\n            axes = [1, 0, *range(2, len(data.shape))]\n            return ops.transpose(data, axes=axes)\n\n        inputs = time_distributed_transpose(inputs)\n        if mask is not None:\n            mask = time_distributed_transpose(mask)","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/keras-team/keras/blob/7a34a03db60bf60042242d6a556fc3be119046a5/keras/src/layers/rnn/time_distributed.py#L82-L118","documentation":"After confirming the mask is at least 2D, TimeDistributed verifies that the mask's first two dimensions (batch and timesteps) equal the input's first two dimensions whenever both are known. A differently-sized mask would be broadcast against the wrong timesteps and silently zero out valid steps, so the layer raises instead.","triggerScenarios":"Passing a mask of shape (batch, other_timesteps) or (other_batch, timesteps) to TimeDistributed; reusing a cached mask from a differently-batched input; a custom compute_mask that hardcodes or slices timesteps incorrectly.","commonSituations":"Padding/truncating sequences to a different maxlen than the mask was built with; splitting batches but reusing the old mask; pipelines that cache masks; stateful RNN reuse across sequences of different lengths.","solutions":["Regenerate the mask from the same input (e.g. keep Embedding(mask_zero=True) immediately upstream so Keras propagates the correct mask)","Make sure sequence padding maxlen matches the mask's timestep dimension","Compare input.shape[:2] vs mask.shape[:2] before calling and reshape or recompute if unequal"],"exampleFix":"# before\nmask = old_mask  # shape (32, 50)\nout = td_layer(x, mask=mask)  # x shape (32, 100)\n\n# after\n# let Keras propagate the mask automatically\nmodel = keras.Sequential([keras.layers.Embedding(vocab, dim, mask_zero=True), td_layer])\nout = model(x)","handlingStrategy":"validation","validationCode":"if mask is not None:\n    ins, msk = tuple(inputs.shape[:2]), tuple(mask.shape[:2])\n    assert ins == msk or None in ins + msk, f'mask {msk} != input {ins}'\nout = td_layer(inputs, mask=mask)","typeGuard":"def mask_matches_input(mask, x) -> bool:\n    return tuple(mask.shape[:2]) == tuple(x.shape[:2])","tryCatchPattern":null,"preventionTips":["Use the same padding maxlen for inputs and masks","Never reuse masks across differently sized batches"],"tags":["keras","time-distributed","masking","dimension-mismatch"],"backgroundTag":"mask-shape-mismatch","analyzedSha":"7a34a03db60bf60042242d6a556fc3be119046a5","analyzedAt":"2026-08-25T21:25:25.994Z","schemaVersion":2},"datasetVersion":"2026-08-26T02:17:13.382Z"}