{"record":{"id":"f85c35b3c9245eed","repo":"keras-team/keras","slug":"cannot-do-batch-dot-on-inputs-with-tf-shapes-x-sh","errorCode":null,"errorMessage":"Cannot do batch_dot on inputs with tf.shapes {x_shape} and {y_shape} with axes={axes}. x.shape[%d] != y.shape[%d] (%d != %d).","messagePattern":"Cannot do batch_dot on inputs with tf\\.shapes (.+?) and (.+?) with axes=(.+?)\\. x\\.shape\\[(.+?)\\] != y\\.shape\\[(.+?)\\] \\((.+?) != (.+?)\\)\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"keras/src/legacy/backend.py","lineNumber":124,"sourceCode":"    if axes[0] < 0:\n        axes[0] += x_ndim\n    if axes[1] < 0:\n        axes[1] += y_ndim\n\n    # sanity checks\n    if 0 in axes:\n        raise ValueError(\n            \"Cannot perform batch_dot over axis 0. \"\n            \"If your inputs are not batched, \"\n            \"add a dummy batch dimension to your \"\n            \"inputs using K.expand_dims(x, 0)\"\n        )\n    a0, a1 = axes\n    d1 = x_shape[a0]\n    d2 = y_shape[a1]\n\n    if d1 is not None and d2 is not None and d1 != d2:\n        raise ValueError(\n            \"Cannot do batch_dot on inputs with tf.shapes \"\n            f\"{x_shape} and {y_shape} with axes={axes}. \"\n            \"x.shape[%d] != y.shape[%d] (%d != %d).\"\n            % (axes[0], axes[1], d1, d2)\n        )\n\n    # backup ndims. Need them later.\n    orig_x_ndim = x_ndim\n    orig_y_ndim = y_ndim\n\n    # if rank is 2, expand to 3.\n    if x_ndim == 2:\n        x = tf.expand_dims(x, 1)\n        a0 += 1\n        x_ndim += 1\n    if y_ndim == 2:\n        y = tf.expand_dims(y, 2)\n        y_ndim += 1","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/keras-team/keras/blob/7a34a03db60bf60042242d6a556fc3be119046a5/keras/src/legacy/backend.py#L106-L142","documentation":"batch_dot() requires the dimension of x selected by axes[0] to equal the dimension of y selected by axes[1]; a batched dot product is only defined for matching contraction sizes. When both static shapes are known and disagree, Keras raises this before touching the graph. The message prints both shapes and the axes so the mismatch can be located by inspection.","triggerScenarios":"batch_dot(x, y, axes=(i, j)) where x.shape[i] != y.shape[j], e.g. x shape (8, 16) dotted with y shape (8, 32) on default axes (1, 1) — contracting 16 against 32.","commonSituations":"Attention layers where query/key feature sizes differ (e.g. after a projection); hand-written merge layers ported from old Keras; transposition mistakes where one operand needs transpose_b or axes=(2,1).","solutions":["Make the contracted dimensions equal: adjust the preceding Dense/kernel so x.shape[axes[0]] == y.shape[axes[1]]","Re-check the axes argument — often you want axes=(2,1) or a transpose on one operand rather than the default","Add/verify a projection layer (Dense to the common size) on the mismatched operand"],"exampleFix":"// before\nout = K.batch_dot(q, k)  # q:(8,16), k:(8,32) -> ValueError\n\n// after\nk_proj = keras.layers.Dense(16)(k)\nout = K.batch_dot(q, k_proj)","handlingStrategy":"validation","validationCode":"assert x.shape[axes[0]] is None or y.shape[axes[1]] is None or x.shape[axes[0]] == y.shape[axes[1]], f'{x.shape} vs {y.shape} on axes {axes}'","typeGuard":"def compatible_batch_dot(x, y, axes=(1, 1)) -> bool:\n    d1, d2 = x.shape[axes[0]], y.shape[axes[1]]\n    return d1 is None or d2 is None or d1 == d2","tryCatchPattern":"except ValueError as e:\n    if 'x.shape' in str(e):\n        raise ValueError(f'contraction dims mismatch — project one side: {e}') from e\n    raise","preventionTips":["Print/assert static shapes before batch_dot in layer tests","Keep query/key projection sizes equal in attention layers","Document which axes each operand is contracted on"],"tags":["keras","tensorflow","batch-dot","dimension-mismatch"],"backgroundTag":"invalid-tensor-shape","analyzedSha":"7a34a03db60bf60042242d6a556fc3be119046a5","analyzedAt":"2026-08-25T21:25:25.994Z","schemaVersion":2},"datasetVersion":"2026-08-26T02:17:13.382Z"}