{"record":{"id":"b5da5050ecb124d8","repo":"jax-ml/jax","slug":"csr-must-have-ndim-2-got-shape","errorCode":null,"errorMessage":"CSR must have ndim=2; got {shape=}","messagePattern":"CSR must have ndim=2; got (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"jax/experimental/sparse/csr.py","lineNumber":88,"sourceCode":"  def dtype(self) -> np.dtype:\n    return self.data.dtype\n\n  def __init__(self, args, *, shape):\n    self.data, self.indices, self.indptr = map(jnp.asarray, args)\n    super().__init__(args, shape=shape)\n\n  @classmethod\n  def fromdense(cls, mat, *, nse=None, index_dtype=np.int32):\n    if nse is None:\n      nse = (mat != 0).sum()\n    return csr_fromdense(mat, nse=nse, index_dtype=index_dtype)\n\n  @classmethod\n  def _empty(cls, shape, *, dtype=None, index_dtype='int32'):\n    \"\"\"Create an empty CSR instance. Public method is sparse.empty().\"\"\"\n    shape = tuple(shape)\n    if len(shape) != 2:\n      raise ValueError(f\"CSR must have ndim=2; got {shape=}\")\n    data = jnp.empty(0, dtype)\n    indices = jnp.empty(0, index_dtype)\n    indptr = jnp.zeros(shape[0] + 1, index_dtype)\n    return cls((data, indices, indptr), shape=shape)\n\n  @classmethod\n  def _eye(cls, N, M, k, *, dtype=None, index_dtype='int32'):\n    if k > 0:\n      diag_size = min(N, M - k)\n    else:\n      diag_size = min(N + k, M)\n\n    if diag_size <= 0:\n      # if k is out of range, return an empty matrix.\n      return cls._empty((N, M), dtype=dtype, index_dtype=index_dtype)\n\n    data = jnp.ones(diag_size, dtype=dtype)\n    idx = jnp.arange(diag_size, dtype=index_dtype)","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jax/experimental/sparse/csr.py#L70-L106","documentation":"The legacy jax.experimental.sparse.CSR format only supports 2D matrices (n rows x m cols with indptr of length n+1). CSR._empty, backing sparse.empty(format='csr') and sparse.eye(format='csr'), validates len(shape) == 2. For higher-dimensional or batched sparse arrays use BCSR or BCOO.","triggerScenarios":"sparse.empty(shape, format='csr') or sparse.eye(..., format='csr') with a shape of length != 2 — e.g. sparse.empty((2,3,4), format='csr') or a 1D shape.","commonSituations":"Extending older 2D CSR code to batched tensors; dynamically choosing formats; migrating from scipy.sparse where ndim is always 2.","solutions":["Use format='bcsr' with n_batch=1 for stacks of matrices, or format='bcoo' for arbitrary layouts","Reshape the tensor into 2D if the legacy CSR API must be used","Prefer BCOO/BCSR in new code — CSR/CSC are legacy wrappers"],"exampleFix":"# before\nm = sparse.empty((8, 16, 16), format='csr')  # ValueError\n\n# after\nm = sparse.empty((8, 16, 16), n_batch=1, format='bcsr')","handlingStrategy":"validation","validationCode":"assert len(tuple(shape)) == 2, 'CSR is 2D only; use bcsr with n_batch or bcoo'","typeGuard":"def csr_shape_ok(shape) -> bool:\n    return len(tuple(shape)) == 2","tryCatchPattern":"try:\n    m = sparse.empty(shape, format='csr')\nexcept ValueError:\n    m = sparse.empty(shape, n_batch=1, format='bcsr')","preventionTips":["Use bcsr/bcoo for batched sparse tensors","Guard format-dispatch code with a 2D check for csr/csc/coo"],"tags":["jax","sparse","csr","shape-validation"],"backgroundTag":"sparse-format-dimension-mismatch","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}