Skip to content

Require mujoco-core 4.0 and remove MuJoCo version shims - #1927

Merged
adenzler-nvidia merged 3 commits into
google-deepmind:mainfrom
adenzler-nvidia:adenzler/mujoco-core-4
Nov 11, 2026
Merged

adenzler-nvidia merged 3 commits into
google-deepmind:mainfrom
adenzler-nvidia:adenzler/mujoco-core-4

Conversation

@adenzler-nvidia

Copy link
Copy Markdown
Collaborator

mujoco-warp declares mujoco>=3.13.0, but it no longer imports with MuJoCo 3.13 through 3.15: ConDataField references mjtConDataField.mjCONDATA_LINVEL at import time since #1813, which fails with AttributeError. This is the same failure #1777 fixed for 3.12, and it went unnoticed because CI never installs the declared minimum. MuJoCo 4.0 also split the Python distribution, so mujoco is now a metapackage that pulls in MuJoCo Studio, Filament, glfw and PyOpenGL on top of mujoco-core. The library uses none of these. Only mjwarp-viewer, mjwarp-record and the tutorial notebook's mujoco.Renderer cells need them.

This change depends on mujoco-core>=4.0.0 and adds a viewer extra (mujoco-core[rendering], pillow) for those tools; dev includes it. pillow was previously only in dev, so mjwarp-record failed on a plain install. benchmarks/run.py --view, the README and the tutorial notebook now use the extra, and the nightly workflow upgrades mujoco-core instead of mujoco. The lock moves to the nightly 4.0.1.dev1017127398, because py.mujoco.org has no final 4.0.0 and 4.0.0.devN sorts below 4.0.0.

Every check_version("mujoco>=...") in the package is satisfied by 4.0.0, so this removes them together with the code they guarded:

  • In put_model and put_data: the eq_data padding, the plasticity and tendon_type defaults, and the host-side surfacevel computation.
  • The rod record size probe, which compiled a model on every import.
  • The kernel branches on ROD_HINGE_SIZE, FLEX_STIFFNESS_3D and FLEX_INTERP_PHYS_JAC. The first two are now plain constants.
  • About 76 version-dependent skips and expected-value switches in the tests.

The flex_internal check in put_model goes too, because MuJoCo 4.0 has no such field. util_pkg.check_version stays, for features of MuJoCo nightlies that haven't been released yet.

The tradeoff is that MuJoCo older than 4.0 is no longer supported. 3.13–3.15 were already broken, and 3.16–3.17 were never tested by CI. The packaging change and the shim removal are independent, so I'm happy to split them if that's easier to review.

mujoco-warp declared mujoco>=3.13.0, but it fails to import with MuJoCo 3.13 through 3.15 because ConDataField references mjtConDataField.mjCONDATA_LINVEL at import time. MuJoCo 4.0 also split the Python distribution: mujoco is now a metapackage that adds MuJoCo Studio, Filament, glfw and PyOpenGL on top of mujoco-core, none of which the library uses.

Depend on mujoco-core>=4.0.0 and add a viewer extra (mujoco-core[rendering], pillow) for mjwarp-viewer, mjwarp-record and mujoco.Renderer. benchmarks/run.py --view, the README and the tutorial notebook use the extra, and the nightly workflow upgrades mujoco-core. The lock moves to the latest MuJoCo nightly, since py.mujoco.org has no final 4.0.0 and 4.0.0 dev builds sort below it.

Every MuJoCo version check is satisfied by 4.0.0, so remove them with the code they guarded: the eq_data padding, plasticity and tendon_type defaults and host-side surfacevel computation in put_model and put_data, the rod record size probe that compiled a model at import, the kernel branches on ROD_HINGE_SIZE, FLEX_STIFFNESS_3D and FLEX_INTERP_PHYS_JAC, and the version-dependent skips and expectations in the tests. The flex_internal check goes too, as MuJoCo 4.0 has no such field. util_pkg.check_version stays for features of unreleased MuJoCo builds.
@adenzler-nvidia

Copy link
Copy Markdown
Collaborator Author

@thowell this is just a suggestion, feel free to close if you think there is a better way to do this.

@thowell thowell left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @adenzler-nvidia! Great cleanup switching to mujoco-core>=4.0.0, adding the viewer extra, and removing the pre-4.0 shims — looks ready to merge once two minor mujoco-core packaging edge cases are addressed:

1. pyproject.toml (lines 49--52) & uv.lock

  • Issue: mjviser in dev declares an unversioned mujoco dependency, which still pulls mujoco and mujoco-studio into uv.lock. Because mujoco was removed from [tool.uv.sources], running uv lock --upgrade-package mujoco-core or uv lock --upgrade (as in .github/workflows/nightly.yml) resolves mujoco from PyPI (mujoco==4.0.0 conflicts with mujoco-core==4.0.1.dev* and backtracks to mujoco==3.17.0), causing uv sync --all-extras to fail on import mujoco (OSError: libmujoco.so.3.17.0: cannot open shared object file).
  • Recommendation: Override the transitive mujoco metapackage dependency under [tool.uv] (mjviser runs directly against mujoco-core[rendering]) and regenerate uv.lock (UV_NO_CONFIG=1 uv lock --default-index https://pypi.org/simple), which also drops mujoco and mujoco-studio from uv.lock.
[tool.uv]
override-dependencies = ["mujoco ; python_version < '0'"]

[tool.uv.sources]
warp-lang = {index = "nvidia"}
mujoco-core = {index = "mujoco"}

2. mujoco_warp/_src/util_pkg.py (lines 75--86)

  • Issue: When only mujoco-core is installed (no mujoco dist-info), util_pkg.check_version("mujoco>=4.0.1.dev...") hits PackageNotFoundError and falls back to mujoco.__version__, which on nightly mujoco-core wheels reports "4.0.1" without the .dev* suffix and falsely evaluates to True against newer .dev* thresholds. Conversely, passing "mujoco-core>=..." without wheel metadata fails in the fallback because the importable module is mujoco.
  • Recommendation: Check both "mujoco" and "mujoco-core" distribution metadata before falling back to importing mujoco.
  dist_names = (
    (package_name, "mujoco-core" if package_name == "mujoco" else "mujoco")
    if package_name in ("mujoco", "mujoco-core")
    else (package_name,)
  )
  for dist_name in dist_names:
    try:
      installed_str = importlib.metadata.version(dist_name)
      break
    except importlib.metadata.PackageNotFoundError:
      pass
  else:
    # Fallback: import the package and read __version__
    try:
      import importlib as _importlib  # noqa: F811

      mod_name = "mujoco" if package_name == "mujoco-core" else package_name
      mod = _importlib.import_module(mod_name)
      installed_str = mod.__version__
    except (ImportError, AttributeError) as err:
      raise importlib.metadata.PackageNotFoundError(package_name) from err

mjviser depends on an unversioned mujoco, which kept the mujoco metapackage and mujoco-studio in uv.lock. Nothing pins that transitive dependency to py.mujoco.org, so when a different index takes priority (for example a default index passed on the command line), upgrading the lock resolves mujoco 3.17 from PyPI next to a mujoco-core 4.0 nightly and the environment no longer imports.

Override the dependency away, since mjviser only needs the mujoco module that mujoco-core provides, and regenerate the lock.
With only mujoco-core installed there is no mujoco distribution, so check_version("mujoco>=...") fell back to mujoco.__version__. That string has no .dev suffix on nightly wheels, so the check passed against newer nightly thresholds. A "mujoco-core>=..." spec without metadata failed in the fallback instead, because the module is named mujoco.

Look up both distribution names before falling back, and import the mujoco module for mujoco-core.
@adenzler-nvidia

Copy link
Copy Markdown
Collaborator Author

Thanks @thowell, both addressed.

  1. Added the mujoco override under [tool.uv] and regenerated uv.lock (af4ca63). mujoco and mujoco-studio are gone from the lock, and uv lock --upgrade / --upgrade-package mujoco-core now give the same result with and without --default-index https://pypi.org/simple. One thing to be aware of: mujoco and mujoco-core both ship mujoco/__init__.py, so syncing an existing venv uninstalls the metapackage and takes that file with it. uv sync --reinstall-package mujoco-core or a fresh venv fixes it; CI is unaffected.

  2. check_version now looks up both the mujoco and mujoco-core distribution metadata before falling back to mujoco.__version__, and the fallback imports mujoco for a mujoco-core spec (8cb5af4). Same behaviour as your snippet, with the name mapping pulled into two module-level dicts, plus tests.

adenzler-nvidia added a commit to adenzler-nvidia/mujoco_warp that referenced this pull request Nov 11, 2026
…at-frames

types_test drops the quaternion field substitution with the other version shims: MjData of MuJoCo 4.0 has xiquat, geom_xquat and site_xquat.

@thowell thowell left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adenzler-nvidia
adenzler-nvidia merged commit 88b3776 into google-deepmind:main Nov 11, 2026
15 checks passed
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.

2 participants