tracel-ai/burn · error

SVD fallback failed: {err}

Error message

SVD fallback failed: {err}

What it means

In `float_svd`, when the backend cannot compute SVD on-device, a CPU host fallback (`svd_host_data`) is used. If the host fallback's decomposition routine fails (e.g. the Jacobi sweep iteration fails to converge or produces invalid data), the code panics with `SVD fallback failed: {err}`. The preceding synchronous data read is also guarded with related expect panics.

Source

Thrown at crates/burn-backend/src/backend/ops/tensor.rs:152

    /// * `swap` - Whether `tensor` is the transpose of the matrix being decomposed.
    ///
    /// # Panics
    ///
    /// The default implementation panics if the input cannot be read
    /// synchronously or if the QR iteration does not converge within the
    /// requested sweep budget.
    fn float_svd(
        tensor: FloatTensor<B>,
        sweeps: usize,
        swap: bool,
    ) -> (FloatTensor<B>, FloatTensor<B>, FloatTensor<B>) {
        let device = tensor.device();
        let msg = "SVD fallback failed to synchronously read tensor data";
        let data = try_read_sync(Self::float_into_data(tensor))
            .expect(msg)
            .expect(msg);
        let (u, s, vt) = super::svd::svd_host_data(data, sweeps, swap)
            .unwrap_or_else(|err| panic!("SVD fallback failed: {err}"));

        (
            Self::float_from_data(u, &device),
            Self::float_from_data(s, &device),
            Self::float_from_data(vt, &device),
        )
    }

    /// Moves the tensor to the given device.
    ///
    /// # Arguments
    ///
    /// * `tensor` - The tensor.
    /// * `device` - The device to move the tensor to.
    ///
    /// # Returns
    ///
    /// The tensor on the given device.

View on GitHub (pinned to d16f7ba2ed)

Solutions

  1. Inspect the embedded `{err}` message to see why svd_host_data failed (convergence vs data issue).
  2. Sanitize the input: remove/replace NaN and Inf values and ensure the matrix is finite before calling svd().
  3. Increase `sweeps` (iteration budget) or adjust `swap` to give the Jacobi fallback more room to converge.
  4. Use a backend with native SVD support or compute SVD via a CPU/linalg library (e.g. ndarray/nalgebra) for pathological inputs.

Example fix

// before
let (u, s, vt) = tensor.svd();

// after
assert!(tensor.clone().into_data().to_vec().iter().all(|v| v.is_finite()));
let (u, s, vt) = tensor.svd(); // or fall back to a CPU linalg crate on error
Defensive patterns

Strategy: fallback

Validate before calling

// check input finiteness before SVD
let data = tensor.clone().into_data();
assert!(data.value.iter().all(|x: &f32| x.is_finite()), "SVD input has NaN/Inf");

Type guard

fn svd_safe(t: &burn::tensor::Tensor<burn::tensor::backend::Backend, 2>) -> bool {
    // finite, non-degenerate 2D input
    t.dims()[0] > 0 && t.dims()[1] > 0
}

Try / catch

// burn panics rather than returning Result; isolate with catch_unwind if SVD may fail
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| tensor.svd()));
match result {
    Ok(usv) => { /* use u, s, vt */ }
    Err(_) => { /* fall back to a CPU linalg crate (nalgebra/ndarray) */ }
}

Prevention

When it happens

Trigger: Calling `tensor.svd()` (float_svd primitive) on a backend without native SVD, where `svd::svd_host_data(data, sweeps, swap)` returns Err — e.g. non-converging Jacobi sweeps, degenerate/NaN/Inf input matrices, or an unsupported matrix shape.

Common situations: Computing SVD on ill-conditioned matrices or matrices containing NaN/Inf; very large matrices exceeding sweep limits; GPU tensors whose sync read returns None; numerically unstable random initialization causing non-convergence.

Related errors


AI-assisted analysis of tracel-ai/burn@d16f7ba2ed (2026-09-05). Data as JSON: /api/errors/a667cabf98bf79b6. Report an issue: GitHub.