diff --git a/python/mujoco/structs.cc b/python/mujoco/structs.cc index 9f616650..1c9e04d9 100644 --- a/python/mujoco/structs.cc +++ b/python/mujoco/structs.cc @@ -77,7 +77,18 @@ py::tuple RecompileSpec(raw::MjSpec* spec, const MjModelWrapper& old_m, raw::MjModel* m = static_cast(mju_malloc(sizeof(mjModel))); m->buffer = nullptr; raw::MjData* d = mj_copyData(nullptr, old_m.get(), old_d.get()); - if (mj_recompile(spec, nullptr, m, d)) { + + bool compile_failed = false; + + { + // Release GIL before calling mj_recompile which may spawn threads + py::gil_scoped_release no_gil; + if (mj_recompile(spec, nullptr, m, d)) { + compile_failed = true; + } + } + + if (compile_failed) { throw py::value_error(mjs_getError(spec)); } diff --git a/python/mujoco/structs_wrappers.cc b/python/mujoco/structs_wrappers.cc index eac086f5..ebfa907b 100644 --- a/python/mujoco/structs_wrappers.cc +++ b/python/mujoco/structs_wrappers.cc @@ -400,7 +400,18 @@ py::tuple RecompileSpec(raw::MjSpec* spec, const MjModelWrapper& old_m, raw::MjModel* m = static_cast(mju_malloc(sizeof(mjModel))); m->buffer = nullptr; raw::MjData* d = mj_copyData(nullptr, old_m.get(), old_d.get()); - if (mj_recompile(spec, nullptr, m, d)) { + + bool compile_failed = false; + + { + // Release GIL before calling mj_recompile which may spawn threads + py::gil_scoped_release no_gil; + if (mj_recompile(spec, nullptr, m, d)) { + compile_failed = true; + } + } + + if (compile_failed) { throw py::value_error(mjs_getError(spec)); }