Troubleshooting
For normal usage, prefer the published wheel:
python -m pip install murk
The maturin develop guidance below is for contributors working on Murk
internals from a source checkout.
Build Issues
Contributor setup: maturin develop fails with “pyo3 not found”
Ensure you have a compatible Python version (3.12+) and that your virtual environment is activated:
python3 -m venv .venv
source .venv/bin/activate
pip install maturin
cd crates/murk-python
maturin develop --release
cargo build fails with MSRV error
Murk requires Rust 1.87 or later. Update with:
rustup update stable
Miri fails to run
Miri requires the nightly toolchain with the miri component:
rustup toolchain install nightly --component miri
cargo +nightly miri test -p murk-arena
Runtime Issues
Python import error: “No module named murk._murk”
If you installed from PyPI, reinstall in the active environment:
python -m pip install --upgrade --force-reinstall murk
If you are working from a source checkout, build the extension in your active virtual environment:
cd crates/murk-python
maturin develop --release
Determinism test failures
Determinism tests are sensitive to floating-point ordering. Ensure you’re running on the same platform and Rust version as CI. See Determinism Guarantees for details.
Import Issues
Contributor setup: maturin develop succeeds but import murk fails
The native extension was built, but Python cannot find it. Check the following:
-
Virtual environment not activated. The extension is installed into the virtualenv that was active during
maturin develop. Make sure you activate the same environment before importing:source .venv/bin/activate python -c "import murk; print(murk.__version__)" -
Python version mismatch. If you have multiple Python versions,
maturin developmay have built against a different one. Verify:python --version # should match the version used during build maturin develop --release # rebuild if in doubt -
Missing numpy. Murk requires numpy >= 1.24. If numpy is not installed, the extension may fail to load:
pip install "numpy>=1.24"
Runtime Performance Issues
Simulation unexpectedly slow
If step throughput is much lower than expected, check these common causes:
-
Debug mode. Ensure you built with
--release. Debug builds are 10-50x slower:maturin develop --release # Python cargo run --release # Rust -
Propagator complexity. A Python propagator that does heavy per-cell work will bottleneck the tick. Profile with
cProfileorpy-spyto confirm. -
Observation extraction frequency. If you are calling
observe()more often than you need observations, reduce the frequency. Each call copies data from the arena. -
Batched vs single env. For RL training with many environments,
BatchedVecEnvsteps all worlds in a single Rust call with one GIL release.MurkVecEnvreleases the GIL N times. Switching toBatchedVecEnvcan yield significant speedups at scale.
CI Failures
Tests pass locally but fail in CI
-
Miri nightly version. Miri is pinned to a specific nightly toolchain. If CI uses a different nightly than your local machine, Miri behaviour may differ. Check the CI configuration for the expected nightly date:
rustup toolchain install nightly-2025-12-01 --component miri cargo +nightly-2025-12-01 miri test -p murk-arena -
Platform differences. Floating-point results can vary across operating systems and CPU architectures. Murk targets Tier B determinism (same build + ISA + toolchain), so cross-platform mismatches are expected for bitwise comparisons.
-
Test isolation. Some tests create temporary files or rely on ordering. If tests run in parallel and share state, they may fail non-deterministically. Use
cargo test -- --test-threads=1to check for isolation issues.
Simulation Behavior Issues
Results don’t match expectations
If the simulation produces unexpected output, check these common causes:
-
Determinism catalogue. Review the Determinism Guarantees page. Some sources of non-determinism (hash ordering, threading, fast-math) are documented with mitigations.
-
Propagator read/write declarations. If a propagator declares
reads(Euler) but should usereads_previous(Jacobi), it will see partially-updated values from earlier propagators in the same tick. Double-check the read mode for each field. -
Timestep too large (CFL violation). If
dtexceeds the CFL stability limit for your propagator, diffusion can blow up or oscillate. The engine checks topology-awaremax_dt(space)at startup, but only if the propagator declares it. Reducedtor add amax_dtdeclaration.