{"record":{"id":"807785066e3d718d","repo":"jax-ml/jax","slug":"convolution-dimension-numbers-must-have-len-eq","errorCode":null,"errorMessage":"convolution dimension_numbers[{}] must have len equal to the ndim of lhs and rhs, got {} for lhs and rhs shapes {} and {}.","messagePattern":"convolution dimension_numbers\\[(.+?)\\] must have len equal to the ndim of lhs and rhs, got (.+?) for lhs and rhs shapes (.+?) and (.+?)\\.","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"jax/_src/lax/convolution.py","lineNumber":982,"sourceCode":"  if len(lhs_shape) != len(rhs_shape):\n    msg = \"convolution requires lhs and rhs ndim to be equal, got {} and {}.\"\n    raise TypeError(msg.format(len(lhs_shape), len(rhs_shape)))\n\n  if dimension_numbers is None:\n    iota = tuple(range(len(lhs_shape)))\n    return ConvDimensionNumbers(iota, iota, iota)\n  elif isinstance(dimension_numbers, (list, tuple)):\n    if len(dimension_numbers) != 3:\n      msg = \"convolution dimension_numbers list/tuple must be length 3, got {}.\"\n      raise TypeError(msg.format(len(dimension_numbers)))\n    if not all(isinstance(elt, str) for elt in dimension_numbers):\n      msg = \"convolution dimension_numbers elements must be strings, got {}.\"\n      raise TypeError(msg.format(tuple(map(type, dimension_numbers))))\n    msg = (\"convolution dimension_numbers[{}] must have len equal to the ndim \"\n           \"of lhs and rhs, got {} for lhs and rhs shapes {} and {}.\")\n    for i, elt in enumerate(dimension_numbers):\n      if len(elt) != len(lhs_shape):\n        raise TypeError(msg.format(i, len(elt), lhs_shape, rhs_shape))\n\n    lhs_spec, rhs_spec, out_spec = conv_general_permutations(dimension_numbers)\n    return ConvDimensionNumbers(lhs_spec, rhs_spec, out_spec)\n  else:\n    msg = \"convolution dimension_numbers must be tuple/list or None, got {}.\"\n    raise TypeError(msg.format(type(dimension_numbers)))\n\n\ndef conv_general_permutations(dimension_numbers):\n  \"\"\"Utility for convolution dimension permutations relative to Conv HLO.\"\"\"\n  lhs_spec, rhs_spec, out_spec = dimension_numbers\n  lhs_char, rhs_char, out_char = charpairs = (\"N\", \"C\"), (\"O\", \"I\"), (\"N\", \"C\")\n  for i, (a, b) in enumerate(charpairs):\n    if not dimension_numbers[i].count(a) == dimension_numbers[i].count(b) == 1:\n      msg = (\"convolution dimension_numbers[{}] must contain the characters \"\n             \"'{}' and '{}' exactly once, got {}.\")\n      raise TypeError(msg.format(i, a, b, dimension_numbers[i]))\n    if len(dimension_numbers[i]) != len(set(dimension_numbers[i])):","sourceCodeStart":964,"sourceCodeEnd":1000,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jax/_src/lax/convolution.py#L964-L1000","documentation":"Each layout string in dimension_numbers must have length equal to the ndim of lhs and rhs. Since lhs/rhs ranks must match (checked just before), any element longer or shorter than the tensor rank raises this TypeError with the offending index, string length, and both shapes.","triggerScenarios":"Passing ('NHWC','HWIO','NHWC') with 3D tensors, or a 5D layout string for 4D tensors, to lax.conv_dimension_numbers / conv_general_dilated.","commonSituations":"Reusing 2D conv layout strings after switching to 1D or 3D data; adding/removing a channel dim without updating the strings.","solutions":["Make each layout string length equal len(lhs_shape) (e.g. 'NHC' for rank-3, 'NHWB C'-style 5 chars for rank-5)","Use distinct spatial characters (e.g. 'NHW' vs 'OID' for width/depth) once ranks grow","Log shapes and layout strings together when debugging"],"exampleFix":"# before\nx = jnp.zeros((8, 28, 3)); w = jnp.zeros((3, 3, 8))\ndn = lax.conv_dimension_numbers(x.shape, w.shape, ('NHWC', 'HWIO', 'NHWC'))\n# after\ndn = lax.conv_dimension_numbers(x.shape, w.shape, ('NHC', 'HIO', 'NHC'))","handlingStrategy":"validation","validationCode":"assert all(len(s) == lhs.ndim for s in dimension_numbers), 'layout length must equal tensor rank'","typeGuard":"def layouts_match_rank(dn, x) -> bool:\n    return all(len(s) == x.ndim for s in dn)","tryCatchPattern":null,"preventionTips":["Generate layout strings from rank: 'N' + 'C' + spatial letters as needed","Re-derive all three strings together when changing data rank"],"tags":["jax","convolution","dimension-numbers","shape-validation"],"backgroundTag":"shape-mismatch","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}