{"record":{"id":"113f4326190a69a9","repo":"jax-ml/jax","slug":"mulhi-operands-must-have-the-same-dtype-got-dtyp","errorCode":null,"errorMessage":"mulhi operands must have the same dtype, got {dtype} and {y_dtype}","messagePattern":"mulhi operands must have the same dtype, got (.+?) and (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"jax/_src/lax_reference.py","lineNumber":120,"sourceCode":"\nadd = np.add\nsub = np.subtract\n\ndef mul(x, y, /, *, out_dtype=None):\n  if out_dtype is not None:\n    x = np.astype(x, out_dtype)\n    y = np.astype(y, out_dtype)\n  return np.multiply(x, y)\n\n\ndef mulhi(x, y):\n  x = np.asarray(x)\n  y = np.asarray(y)\n  dtype = x.dtype\n  if not np.issubdtype(dtype, np.integer):\n    raise TypeError(f'mulhi requires integer inputs, got {dtype}')\n  if dtype != y.dtype:\n    raise TypeError(\n        f'mulhi operands must have the same dtype, got {dtype} and {y.dtype}'\n    )\n  info = np.iinfo(dtype)\n  bits = info.bits\n  is_signed = np.issubdtype(dtype, np.signedinteger)\n  # For 64-bit inputs, use Python object dtype for arbitrary precision.\n  if bits == 64:\n    widen_dtype = np.dtype(object)\n  else:\n    widen_bits = bits * 2\n    widen_dtype = np.dtype(f'{\"i\" if is_signed else \"u\"}{widen_bits // 8}')\n  prod = x.astype(widen_dtype) * y.astype(widen_dtype)\n  return (prod >> bits).astype(dtype)\n\n\ndef div(lhs, rhs):\n  if dtypes.issubdtype(dtypes.result_type(lhs), np.integer):\n    quotient = np.floor_divide(lhs, rhs)","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jax/_src/lax_reference.py#L102-L138","documentation":"mulhi's high-word extraction assumes both operands share the same integer width. The reference implementation fires when x.dtype differs from y.dtype, e.g. multiplying int32 by int64, which would change the number of high bits.","triggerScenarios":"lax_reference.mulhi(np.int32(x), np.int64(y)) or mixing Python ints (int64) with explicit int32 arrays.","commonSituations":"Fixed-point arithmetic where one operand came from np.arange defaults and the other was explicitly cast; NumPy scalar promotion differences across versions.","solutions":["Cast both operands to the same dtype before calling: np.int32 promotion of both","Use jnp int dtype explicitly on all inputs (np.arange(..., dtype=np.int32))"],"exampleFix":"# before\nlax_reference.mulhi(a.astype(np.int32), b)  # b is int64\n# after\nlax_reference.mulhi(a.astype(np.int32), b.astype(np.int32))","handlingStrategy":"validation","validationCode":"x, y = np.asarray(x), np.asarray(y)\nassert x.dtype == y.dtype, f'{x.dtype} vs {y.dtype}'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set dtype= on all producing ops (arange, ones) to a fixed int width"],"tags":["jax","dtype","mulhi","type-mismatch"],"backgroundTag":"dtype-mismatch-between-operands","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}