{"record":{"id":"310c6e18fbff32fc","repo":"keras-team/keras","slug":"a-concatenate-layer-should-be-called-on-a-list-o-310c6e","errorCode":null,"errorMessage":"A `Concatenate` layer should be called on a list of inputs. Received: input_shape={input_shape}","messagePattern":"A `Concatenate` layer should be called on a list of inputs\\. Received: input_shape=(.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"keras/src/layers/merging/concatenate.py","lineNumber":108,"sourceCode":"            for axis in range(rank):\n                # Skip the Nones in the shape since they are dynamic, also the\n                # axis for concat has been removed above.\n                unique_dims = set(\n                    shape[axis]\n                    for shape in shape_set\n                    if shape[axis] is not None\n                )\n                if len(unique_dims) > 1:\n                    raise ValueError(err_msg)\n\n    def _merge_function(self, inputs):\n        return ops.concatenate(inputs, axis=self.axis)\n\n    def compute_output_shape(self, input_shape):\n        if (not isinstance(input_shape, (tuple, list))) or (\n            not isinstance(input_shape[0], (tuple, list))\n        ):\n            raise ValueError(\n                \"A `Concatenate` layer should be called on a list of inputs. \"\n                f\"Received: input_shape={input_shape}\"\n            )\n        input_shapes = input_shape\n        output_shape = list(input_shapes[0])\n\n        for shape in input_shapes[1:]:\n            if output_shape[self.axis] is None or shape[self.axis] is None:\n                output_shape[self.axis] = None\n                break\n            output_shape[self.axis] += shape[self.axis]\n        return tuple(output_shape)\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}\")","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/keras-team/keras/blob/7a34a03db60bf60042242d6a556fc3be119046a5/keras/src/layers/merging/concatenate.py#L90-L126","documentation":"Concatenate.compute_output_shape requires input_shape to be a list of shapes (input_shape[0] itself a tuple/list). If called with a single tensor's shape, the shape math for concatenation cannot proceed and this ValueError is raised.","triggerScenarios":"Calling compute_output_shape((None, 10)) directly; Functional model graph construction where the concat layer is wired to a single input; subclass overriding and forwarding a bare shape.","commonSituations":"Programmatic shape inference on models; incorrect list nesting when building functional models; debugging utilities calling compute_output_shape with unwrapped shapes.","solutions":["Pass a list of shapes: layer.compute_output_shape([s1, s2])","In Functional graphs, ensure the concat node receives a list of input tensors","Fix custom layers that forward single shapes into Concatenate.compute_output_shape"],"exampleFix":"# before\nshape = concat.compute_output_shape((None, 10))\n\n# after\nshape = concat.compute_output_shape([(None, 10), (None, 20)])","handlingStrategy":"validation","validationCode":"assert isinstance(input_shape, (list, tuple)) and isinstance(input_shape[0], (list, tuple))","typeGuard":"def is_shape_list(input_shape) -> bool:\n    return isinstance(input_shape, (list, tuple)) and len(input_shape) > 0 and isinstance(input_shape[0], (list, tuple))","tryCatchPattern":null,"preventionTips":["When calling compute_output_shape manually, pass a list of shapes","Keep Functional graph wiring list-shaped at multi-input nodes"],"tags":["keras","concatenate","shape-inference","input-format"],"backgroundTag":"wrong-argument-structure","analyzedSha":"7a34a03db60bf60042242d6a556fc3be119046a5","analyzedAt":"2026-08-25T21:25:25.994Z","schemaVersion":2},"datasetVersion":"2026-08-26T02:17:13.382Z"}