{"record":{"id":"765ba5e6e9617cd9","repo":"jax-ml/jax","slug":"need-sequence-of-keys-with-len-0-in-lexsort","errorCode":null,"errorMessage":"need sequence of keys with len > 0 in lexsort","messagePattern":"need sequence of keys with len > 0 in lexsort","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"jax/_src/numpy/sorting.py","lineNumber":430,"sourceCode":"\n    >>> key1 = jnp.array([[2, 4, 2, 3],\n    ...                   [3, 1, 2, 2]])\n    >>> key2 = jnp.array([[1, 2, 1, 3],\n    ...                   [2, 1, 2, 1]])\n    >>> jnp.lexsort([key1, key2])\n    Array([[0, 2, 1, 3],\n           [1, 3, 2, 0]], dtype=int32)\n\n    A different sort axis can be chosen using the ``axis`` keyword; here we sort\n    along the leading axis:\n\n    >>> jnp.lexsort([key1, key2], axis=0)\n    Array([[0, 1, 0, 1],\n           [1, 0, 1, 0]], dtype=int32)\n  \"\"\"\n  key_arrays = util.ensure_arraylike_tuple(\"lexsort\", tuple(keys))\n  if len(key_arrays) == 0:\n    raise TypeError(\"need sequence of keys with len > 0 in lexsort\")\n  if len({np.shape(key) for key in key_arrays}) > 1:\n    raise ValueError(\"all keys need to be the same shape\")\n  if np.ndim(key_arrays[0]) == 0:\n    return lax.full((), 0, dtypes.default_int_dtype())\n  axis = canonicalize_axis(axis, np.ndim(key_arrays[0]))\n  idx_dtype = lax_utils.int_dtype_for_dim(key_arrays[0].shape[axis],\n                                          signed=True)\n  # We'd give the correct output values with int32, but use the default dtype to\n  # match NumPy type semantics if x64 mode is enabled for now.\n  if idx_dtype == np.dtype(np.int32):\n    idx_dtype = dtypes.default_int_dtype()\n  iota = lax.broadcasted_iota(idx_dtype, np.shape(key_arrays[0]), axis)\n  return lax.sort((*key_arrays[::-1], iota), dimension=axis, num_keys=len(key_arrays))[-1]\n\n\n@export\n@api.jit(static_argnums=1, static_argnames=('axis', 'mode', 'sorted'))\ndef top_k(","sourceCodeStart":412,"sourceCodeEnd":448,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jax/_src/numpy/sorting.py#L412-L448","documentation":"jnp.lexsort requires at least one sort key; passing an empty sequence is a TypeError because there is nothing to define an ordering. NumPy similarly errors, and JAX mirrors that contract. The check fires on len(keys) == 0 after input conversion.","triggerScenarios":"Calling jnp.lexsort([]) or jnp.lexsort(tuple()) — typically because a keys list was built dynamically (e.g., [k for k in ... if pred]) and ended up empty.","commonSituations":"Programmatically building a key list from user input or config that can be empty; refactoring multi-key sorts so the key list is computed rather than hardcoded; default-argument bugs where keys=None is converted to an empty tuple.","solutions":["Guard the call: only invoke lexsort when the keys list is non-empty","Provide a fallback ordering when no keys exist (e.g., use arange for identity order)","Fix the upstream logic that produced an empty key list"],"exampleFix":"# before\norder = jnp.lexsort(keys)  # keys may be []\n# after\norder = jnp.lexsort(keys) if keys else jnp.arange(n)","handlingStrategy":"validation","validationCode":"assert len(keys) > 0, 'lexsort needs at least one key'","typeGuard":"def valid_lexsort_keys(keys) -> bool:\n    return len(keys) > 0","tryCatchPattern":null,"preventionTips":["Never build the key list without a default key","Validate dynamically built key lists at the boundary","Add a primary key constant so the list is never empty"],"tags":["jax","lexsort","empty-input","validation","sorting"],"backgroundTag":"empty-sequence-validation","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}