Skip to content

feat: raise proper Python exceptions instead of panicking - #4

Merged
asjad2401 merged 3 commits into
mainfrom
fix/error-handling
Oct 5, 2026
Merged

asjad2401 merged 3 commits into
mainfrom
fix/error-handling

Conversation

@asjad2401

Copy link
Copy Markdown
Owner

Stacked on #3 — merge that first (this PR's base will retarget to main).

Summary

Every failure path used to be an .expect() / panic!, which reaches Python as pyo3_runtime.PanicException (a BaseException, so except Exception doesn't catch it). Now:

Situation Before After
float64 / list input pyo3 conversion error TypeError: input 'x': expected a float32 array, got float64 (use .astype(np.float32))
wrong rank / static dim panic deep in an op ValueError: input 'x': expected shape [?, 3], got shape [2, 4]
op or backend failure PanicException + Rust stderr dump RuntimeError: node 'gemm1' (Gemm): matmul: inner dimensions must match ...
missing output panic RuntimeError: model output 'y' was never computed

How:

  • Ops return OpResult; ExecutionContext::require replaces .expect() on inputs.
  • Each node runs under catch_unwind, so panics inside Burn are converted too, with node name and op type attached.
  • The default panic hook is silenced (the message is already in the exception) unless RUST_BACKTRACE is set.

Bug fix found along the way

Fortran-ordered inputs such as x.T were read in memory order, silently scrambling the data — rust-numpy's as_slice() succeeds for F-contiguous arrays too. Only C-contiguous arrays now take the fast path; everything else is gathered in logical order.

Testing

tests/test_ops.py gains error-path cases (dtype, non-array, rank, static dim, input count, backend panic → RuntimeError) and non-contiguous inputs (transposed, strided, negative stride). All 24 checks pass, plus test_bridge.py, compare_ort.py, cargo fmt --check, and clippy -D warnings.

Note

Node names in errors are onnx-ir's generated names (gemm1), not the original names in the ONNX file — onnx-ir renames nodes during parsing.

🤖 Generated with Claude Code

- Ops return Result; ExecutionContext::require replaces .expect() on inputs.
- Each node runs under catch_unwind so backend panics become RuntimeError
  with node name and op type. Default panic hook is silenced unless
  RUST_BACKTRACE is set, since the message is carried in the exception.
- Validate inputs up front: TypeError for non-ndarray / non-float32,
  ValueError for wrong count, rank or static dims.
- Fix Fortran-ordered inputs (e.g. x.T) being read in memory order;
  only C-contiguous arrays take the fast path.
- flex_to_numpy returns PyResult instead of panicking.
- Extend tests/test_ops.py with error-path and non-contiguous cases.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Base automatically changed from fix/padding-reshape-unsupported-ops to main October 5, 2026 14:27
@asjad2401
asjad2401 merged commit eae3921 into main Oct 5, 2026
4 checks passed
@asjad2401
asjad2401 deleted the fix/error-handling branch October 5, 2026 14:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant