{"record":{"id":"31c13d7fa9aa9706","repo":"jax-ml/jax","slug":"input-t-must-be-square","errorCode":null,"errorMessage":"Input 'T' must be square.","messagePattern":"Input 'T' must be square\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"jax/_src/scipy/linalg.py","lineNumber":2329,"sourceCode":"    [[ 3.76 -2.17  1.38]\n     [ 0.   -0.88 -0.35]\n     [ 0.    2.37 -0.88]]\n\n    By contrast, the complex form is truly upper-triangular:\n\n    >>> with jnp.printoptions(precision=2, suppress=True):\n    ...   print(Tc)\n    [[ 3.76+0.j    1.29-0.78j  2.02-0.5j ]\n     [ 0.  +0.j   -0.88+0.91j -2.02+0.j  ]\n     [ 0.  +0.j    0.  +0.j   -0.88-0.91j]]\n  \"\"\"\n  del check_finite  # unused\n\n  T_arr = jnp.asarray(T)\n  Z_arr = jnp.asarray(Z)\n\n  if T_arr.ndim < 2 or T_arr.shape[-1] != T_arr.shape[-2]:\n    raise ValueError(\"Input 'T' must be square.\")\n  if Z_arr.ndim < 2 or Z_arr.shape[-1] != Z_arr.shape[-2]:\n    raise ValueError(\"Input 'Z' must be square.\")\n  if T_arr.shape[-1] != Z_arr.shape[-1]:\n    raise ValueError(f\"Input array shapes must match: Z: {Z_arr.shape} vs. T: {T_arr.shape}\")\n\n  return jnp_vectorize.vectorize(\n      _rsf2csf_2d, signature=\"(n,n),(n,n)->(n,n),(n,n)\")(T_arr, Z_arr)\n\n@overload\ndef hessenberg(a: ArrayLike, *, calc_q: Literal[False], overwrite_a: bool = False,\n               check_finite: bool = True) -> Array: ...\n\n@overload\ndef hessenberg(a: ArrayLike, *, calc_q: Literal[True], overwrite_a: bool = False,\n               check_finite: bool = True) -> tuple[Array, Array]: ...\n\n\n@jit(static_argnames=('calc_q', 'check_finite', 'overwrite_a'))","sourceCodeStart":2311,"sourceCodeEnd":2347,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jax/_src/scipy/linalg.py#L2311-L2347","documentation":"jax.scipy.linalg.rsf2csf converts a real Schur form to complex Schur form; the quasi-triangular T matrix must be a (batched) square matrix. The validation rejects arrays with fewer than 2 dimensions or whose last two axes differ in size (shape[-1] != shape[-2]).","triggerScenarios":"Passing a 1-D array or a ragged/non-square last-two-dims array as T, e.g. shape (3, 4) or (2, 2, 3, 4).","commonSituations":"Feeding the output of schur() that was reshaped/sliced incorrectly; passing a vector of eigenvalues instead of the Schur factor; batched pipelines with a malformed batch member.","solutions":["Ensure T comes from scipy_schur/schur output or another square matrix source","Check T.shape[-1] == T.shape[-2] and T.ndim >= 2 before calling","Fix upstream slicing that dropped an axis (e.g. T[0] vs T[:, 0])"],"exampleFix":"# before\nTc, Zc = rsf2csf(t_vec, z)  # t_vec shape (n,)\n# after\nTc, Zc = rsf2csf(t_vec.reshape(-1, 1), z)","handlingStrategy":"validation","validationCode":"T = jnp.asarray(T)\nif T.ndim < 2 or T.shape[-1] != T.shape[-2]:\n    raise ValueError(f\"T must be square, got {T.shape}\")\nTc, Zc = rsf2csf(T, Z)","typeGuard":"def is_square_matrix(x) -> bool:\n    x = jnp.asarray(x)\n    return x.ndim >= 2 and x.shape[-1] == x.shape[-2]","tryCatchPattern":"try:\n    rsf2csf(T, Z)\nexcept ValueError as e:\n    if \"must be square\" in str(e):\n        raise ValueError(f'bad Schur factors: {e}') from e\n    raise","preventionTips":["Always source T and Z from the same schur(calc_q=True) call","Add shape assertions after any slicing of decomposition factors","Unit-test decomposition plumbing with random square matrices of several sizes"],"tags":["jax","rsf2csf","schur-form","shape-validation"],"backgroundTag":"expected-square-matrix","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}