{"record":{"id":"eb750866a16bcd79","repo":"keras-team/keras","slug":"mask-should-be-a-list-received-mask-mask","errorCode":null,"errorMessage":"`mask` should be a list. Received: mask={mask}","messagePattern":"`mask` should be a list\\. Received: mask=(.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"keras/src/layers/merging/base_merge.py","lineNumber":259,"sourceCode":"        batch_sizes = {s[0] for s in input_shape if s is not None} - {None}\n        if len(batch_sizes) == 1:\n            output_shape = (list(batch_sizes)[0],) + output_shape\n        else:\n            output_shape = (None,) + output_shape\n        return output_shape\n\n    def compute_output_spec(self, inputs):\n        output_shape = self.compute_output_shape([x.shape for x in inputs])\n        output_sparse = all(x.sparse for x in inputs)\n        return KerasTensor(\n            output_shape, dtype=self.compute_dtype, sparse=output_sparse\n        )\n\n    def compute_mask(self, inputs, mask=None):\n        if mask is None:\n            return None\n        if not isinstance(mask, (tuple, list)):\n            raise ValueError(f\"`mask` should be a list. Received: mask={mask}\")\n        if not isinstance(inputs, (tuple, list)):\n            raise ValueError(\n                f\"`inputs` should be a list. Received: inputs={inputs}\"\n            )\n        if len(mask) != len(inputs):\n            raise ValueError(\n                \"The lists `inputs` and `mask` should have the same length. \"\n                f\"Received: inputs={inputs} of length {len(inputs)}, and \"\n                f\"mask={mask} of length {len(mask)}\"\n            )\n        # Default implementation does an OR between the masks, which works\n        # for `Add`, `Subtract`, `Average`, `Maximum`, `Minimum`, `Multiply`.\n        if any(m is None for m in mask):\n            return None\n        output_mask = mask[0]\n        for m in mask[1:]:\n            output_mask = ops.logical_or(output_mask, m)\n        return output_mask","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/keras-team/keras/blob/7a34a03db60bf60042242d6a556fc3be119046a5/keras/src/layers/merging/base_merge.py#L241-L277","documentation":"Merge.compute_mask() requires that when a mask is provided it is a list/tuple parallel to the inputs. This error fires when mask is a single mask tensor (or any non-sequence) while the layer has multiple inputs.","triggerScenarios":"Calling a merge layer with mask=single_tensor on multi-input merge layers; custom layers overriding compute_mask and passing a bare mask upstream.","commonSituations":"Masking (variable-length sequences) feeding a merge layer; passing an Embedding(mask_zero=True) output mask directly instead of as a list.","solutions":["Pass mask as a list parallel to inputs: merge([x1, x2], mask=[m1, m2])","Use None entries where an input has no mask: mask=[m1, None]","Ensure custom layers wrap masks into lists before delegating to merge compute_mask"],"exampleFix":"# before\nout = merge([x1, x2], mask=m)\n\n# after\nout = merge([x1, x2], mask=[m, m])","handlingStrategy":"validation","validationCode":"assert mask is None or isinstance(mask, (list, tuple)), 'mask must be a list parallel to inputs'","typeGuard":"def is_mask_list(mask) -> bool:\n    return mask is None or isinstance(mask, (list, tuple))","tryCatchPattern":null,"preventionTips":["Pass masks as lists with None placeholders","Rely on automatic mask propagation when possible"],"tags":["keras","merge","masking"],"backgroundTag":"wrong-argument-structure","analyzedSha":"7a34a03db60bf60042242d6a556fc3be119046a5","analyzedAt":"2026-08-25T21:25:25.994Z","schemaVersion":2},"datasetVersion":"2026-08-26T02:17:13.382Z"}