{"record":{"id":"8dfb6efbe0d34e75","repo":"keras-team/keras","slug":"input-x-should-be-a-tuple-of-two-tensors-real-8dfb6e","errorCode":null,"errorMessage":"Input `x` should be a tuple of two tensors - real and imaginary. Received: x={x}","messagePattern":"Input `x` should be a tuple of two tensors - real and imaginary\\. Received: x=(.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"keras/src/ops/math.py","lineNumber":501,"sourceCode":"\n    Example:\n\n    >>> x = keras.ops.convert_to_tensor([1, 2, 3, 4, 5, 6])\n    >>> extract_sequences(x, 3, 2)\n    array([[1, 2, 3],\n       [3, 4, 5]])\n    \"\"\"\n    if any_symbolic_tensors((x,)):\n        return ExtractSequences(sequence_length, sequence_stride).symbolic_call(\n            x\n        )\n    return backend.math.extract_sequences(x, sequence_length, sequence_stride)\n\n\nclass FFT(Operation):\n    def compute_output_spec(self, x):\n        if not isinstance(x, (tuple, list)) or len(x) != 2:\n            raise ValueError(\n                \"Input `x` should be a tuple of two tensors - real and \"\n                f\"imaginary. Received: x={x}\"\n            )\n\n        real, imag = x\n        # Both real and imaginary parts should have the same shape.\n        if real.shape != imag.shape:\n            raise ValueError(\n                \"Input `x` should be a tuple of two tensors - real and \"\n                \"imaginary. Both the real and imaginary parts should have the \"\n                f\"same shape. Received: x[0].shape = {real.shape}, \"\n                f\"x[1].shape = {imag.shape}\"\n            )\n\n        # We are calculating 1D FFT. Hence, rank >= 1.\n        if len(real.shape) < 1:\n            raise ValueError(\n                f\"Input should have rank >= 1. \"","sourceCodeStart":483,"sourceCodeEnd":519,"githubUrl":"https://github.com/keras-team/keras/blob/7a34a03db60bf60042242d6a556fc3be119046a5/keras/src/ops/math.py#L483-L519","documentation":"keras.ops.fft (1D FFT) requires its input to be a tuple/list of exactly two tensors: the real and imaginary parts of a complex signal. During symbolic shape inference (compute_output_spec), the op rejects anything that is not a 2-element sequence, such as a single tensor or a numpy array.","triggerScenarios":"Calling keras.ops.fft(x) with a single real tensor, a stack of real+imag along an axis, a list of 3+ tensors, or a plain numpy array instead of a tuple of two KerasTensors.","commonSituations":"Migrating code from np.fft.fft or torch.fft (which take one complex tensor) to Keras 3, or assuming Keras auto-converts complex inputs; also passing the output of zip or an unpacked *args incorrectly.","solutions":["Pass a tuple (real, imag): keras.ops.fft((real, imag))","If you have one complex-valued tensor, split it into its real and imag halves before calling","Use keras.ops.stft or keras.ops.rfft for real-only signals instead of fft","Check len(x)==2 and that both elements are tensors before the call in data pipelines"],"exampleFix":"# before\nspec = keras.ops.fft(signal)\n# after\nspec = keras.ops.fft((signal_real, signal_imag))","handlingStrategy":"type-guard","validationCode":"assert isinstance(x, (tuple, list)) and len(x) == 2, 'fft expects (real, imag)'","typeGuard":"def is_complex_pair(x):\n    return isinstance(x, (tuple, list)) and len(x) == 2","tryCatchPattern":null,"preventionTips":["Always construct the (real, imag) tuple at the call site","Keep FFT inputs as the 2-tuple produced by other keras FFT ops"],"tags":["keras","fft","input-validation","shape"],"backgroundTag":"invalid-function-arguments","analyzedSha":"7a34a03db60bf60042242d6a556fc3be119046a5","analyzedAt":"2026-08-25T21:25:25.994Z","schemaVersion":2},"datasetVersion":"2026-08-26T02:17:13.382Z"}