keras-team/keras · error · ValueError

Cholesky decomposition failed: {e}

Error message

Cholesky decomposition failed: {e}

What it means

The Cholesky op validates 2D square input, then delegates to backend.linalg.cholesky; any backend exception (typically a non-positive-definite or non-Hermitian matrix) is wrapped in this ValueError, with the backend's numeric failure text embedded.

Source

Thrown at keras/src/ops/linalg.py:48

        upper (bool): If True, returns the upper-triangular Cholesky factor.
            If False (default), returns the lower-triangular Cholesky factor.

    Returns:
        A tensor of shape `(..., M, M)` representing the Cholesky factor of `x`.
    """
    if any_symbolic_tensors((x,)):
        return Cholesky(upper=upper).symbolic_call(x)
    return _cholesky(x, upper=upper)


def _cholesky(x, upper=False):
    x = backend.convert_to_tensor(x)
    _assert_2d(x)
    _assert_square(x)
    try:
        return backend.linalg.cholesky(x, upper=upper)
    except Exception as e:
        raise ValueError(f"Cholesky decomposition failed: {e}")


class CholeskyInverse(Operation):
    def __init__(self, upper=False, *, name=None):
        super().__init__(name=name)
        self.upper = upper

    def call(self, x):
        return _cholesky_inverse(x, self.upper)

    def compute_output_spec(self, x):
        _assert_2d(x)
        _assert_square(x)
        return KerasTensor(x.shape, x.dtype)


@keras_export(
    ["keras.ops.cholesky_inverse", "keras.ops.linalg.cholesky_inverse"]

View on GitHub (pinned to 7a34a03db6)

Solutions

  1. Check eigenvalues: the smallest must be > 0; fix matrix construction if not.
  2. Add jitter to the diagonal: x + eps * eye(n) with eps ~1e-6..1e-3.
  3. If symmetry was lost numerically, symmetrize: (x + x.T) / 2.
  4. If semi-definite is intended, use eigenvalue clipping or a sqrtm-based path instead of Cholesky.

Example fix

# before
L = keras.ops.linalg.cholesky(cov)

# after
import numpy as np
cov_reg = cov + 1e-6 * np.eye(cov.shape[-1])
L = keras.ops.linalg.cholesky(cov_reg)
Defensive patterns

Strategy: try-catch

Validate before calling

import numpy as np
eigvals = np.linalg.eigvalsh(np.asarray(x))
if eigvals.min() <= 0:
    x = x + (abs(eigvals.min()) + 1e-6) * np.eye(x.shape[-1])

Type guard

def is_spd(x, tol=1e-10):
    x = np.asarray(x)
    return x.ndim == 2 and x.shape[0] == x.shape[1] and np.allclose(x, x.T) and np.linalg.eigvalsh(x).min() > tol

Try / catch

try:
    L = keras.ops.linalg.cholesky(x)
except ValueError as e:
    if 'Cholesky decomposition failed' in str(e):
        L = keras.ops.linalg.cholesky(x + 1e-6 * np.eye(x.shape[-1]))
    else:
        raise

Prevention

When it happens

Trigger: keras.ops.linalg.cholesky(cov) where cov has negative or zero eigenvalues; a covariance matrix estimated from fewer samples than dimensions; matrices with numerical asymmetry from float error.

Common situations: Gaussian-process or multivariate-normal sampling code; Cholesky-based preconditioners; a model parameterizing a matrix meant to be SPD whose eigenvalues drift to zero during training.

Related errors


AI-assisted analysis of keras-team/keras@7a34a03db6 (2026-08-25). Data as JSON: /api/errors/8431acd29a418e30. Report an issue: GitHub.