Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Error model

matten uses a single public error type, MattenError, and splits every API into one of two zones. Understanding the split is the key to writing correct code with matten.

Panic zone vs Result zone

ZoneWhenHow
Panic zoneLocal, developer-authored PoC code where shapes are knownAPI panics with an actionable matten <category> error in <operation>: ... message
Result zoneAny external boundary — parsing, file I/O, user-supplied shapesAPI returns Result<Tensor, MattenError> and never panics on ordinary invalid input

Rule of thumb: if the shape or data comes from outside your code (a file, a web request, user input), use the try_* form.

#![allow(unused)]
fn main() {
use matten::{MattenError, Tensor};

// Panic zone: shape is a trusted literal
let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);

// Result zone: shape comes from somewhere external
let result = Tensor::try_new(data, &user_shape);
match result {
    Ok(t) => println!("{t:?}"),
    Err(e) => eprintln!("bad input: {e}"),
}
}

MattenError variants

#![allow(unused)]
fn main() {
#[derive(Debug)]
#[non_exhaustive]
pub enum MattenError {
    Shape     { operation: &'static str, message: String },
    Broadcast { left: Vec<usize>, right: Vec<usize> },
    Allocation { requested_elements: usize, message: String },
    Slice     { input: Option<String>, message: String },
    Parse     { format: DataFormat, message: String },
    Io        { path: std::path::PathBuf, source: std::io::Error },
    Unsupported { operation: &'static str, message: String },
    InvalidArgument { operation: &'static str, argument: &'static str, message: String },
}
}

MattenError is #[non_exhaustive], so match it with a wildcard arm to stay forward-compatible.

DataFormat identifies which parser produced a Parse error:

#![allow(unused)]
fn main() {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum DataFormat { Json, Csv }
}

Variant guide

VariantProduced by
Shapeconstruction mismatch, reshape, invalid arange arguments
Broadcastincompatible operand shapes in arithmetic
Allocationshape product overflow or arange element-count limit
Sliceslice builder bounds errors, slice_str parse/bounds errors
Parsefrom_json, from_csv, and their file-loading variants
Ioload_json, load_csv file I/O errors
Unsupporteddisabled-feature or not-yet-implemented operation, or a numeric-only API called on a dynamic tensor
InvalidArgumenta supported operation given an out-of-range/ill-defined argument (e.g. clip with min > max); distinct from Unsupported

Matching errors

MattenError embeds std::io::Error in Io, which is neither Clone nor PartialEq. Never compare with ==; always match by variant.

#![allow(unused)]
fn main() {
let err = Tensor::try_new(vec![1.0], &[2, 2]).unwrap_err();

// correct
assert!(matches!(err, MattenError::Shape { .. }));

// correct
if let MattenError::Shape { operation, message } = &err {
    println!("{operation}: {message}");
}

// will not compile — MattenError does not implement PartialEq
// assert_eq!(err, MattenError::Shape { .. });
}

Panic message format

Panic-zone APIs always begin with "matten":

matten shape error in reshape: cannot reshape tensor with 6 elements
    from shape [2, 3] into shape [4, 2] requiring 8 elements

The format is matten <category> error in <operation>: <detail>. When something panics unexpectedly, this prefix makes it easy to grep.

Using ? in application code

MattenError implements std::error::Error, so it works with ? and Box<dyn Error>:

#![allow(unused)]
fn main() {
fn load_and_process(path: &str) -> Result<Tensor, Box<dyn std::error::Error>> {
    let t = Tensor::load_json(path)?;  // Io or Parse on failure
    let flat = t.try_reshape(&[t.len()])?;  // Shape on mismatch
    Ok(flat)
}
}