Implementation:Google deepmind Dm control MJCF Debugging
| Knowledge Sources | |
|---|---|
| Domains | Robotics Simulation, Developer Tooling |
| Last Updated | 2026-02-15 04:00 GMT |
Overview
The debugging module implements PyMJCF's debug mode, which records Python stack traces whenever the MJCF object model is modified, enabling users to trace MuJoCo compile errors back to the originating Python source lines.
Description
When debug mode is enabled (via the --pymjcf_debug command-line flag or the enable_debug_mode() function), every attribute assignment and element creation in the MJCF object model captures a StackTraceEntry named tuple list. The stack trace is truncated at PyMJCF's internal module boundary, so users see only their own code. The freeze_current_stack_trace() context manager caches the stack during bulk operations (such as XML parsing or deep element creation) for performance, preventing the same stack trace from being repeatedly constructed.
The DebugContext class is the central component used during XML generation. It tags each MJCF element with an XML comment containing a unique ID (the Python object id) and stores an ElementDebugInfo named tuple containing the element reference, its creation stack trace, and the last-modified stack traces for all attributes. When MuJoCo raises a compile error, the process_and_raise_last_exception() method parses the error's line number from the MuJoCo error message, finds the corresponding XML line, extracts the debug metadata comment, looks up the associated ElementDebugInfo, and re-raises the exception with the original Python creation/modification stack traces appended to the error message. The commit_xml_string() method reformats the XML so debug metadata comments appear on the same line as their corresponding elements.
Full debug information can be dumped to disk via dump_full_debug_info_to_disk(), creating an XML file with element IDs and individual .dump files for each element containing creation and attribute modification stack traces.
Usage
Enable debug mode when diagnosing MuJoCo compile errors in programmatically generated models. This is particularly useful for complex models built via the composer framework where the source of a malformed element may be difficult to locate. Note that debug mode has significant performance overhead and should not be used in production.
Code Reference
Source Location
- Repository: Google_deepmind_Dm_control
- File: dm_control/mjcf/debugging.py
- Lines: 1-366
Signature
def debug_mode() -> bool: ...
def enable_debug_mode() -> None: ...
def disable_debug_mode() -> None: ...
def get_full_dump_dir() -> str: ...
def set_full_dump_dir(dump_path: str) -> None: ...
def get_current_stack_trace() -> list[StackTraceEntry]: ...
@contextlib.contextmanager
def freeze_current_stack_trace():
"""Context manager that freezes the stack trace for bulk operations."""
...
class DebugContext:
def register_element_for_debugging(self, elem): ...
def commit_xml_string(self, xml_string): ...
def process_and_raise_last_exception(self): ...
def dump_full_debug_info_to_disk(self, dump_dir=None): ...
StackTraceEntry = collections.namedtuple(
'StackTraceEntry', ('filename', 'line_number', 'function_name', 'text'))
ElementDebugInfo = collections.namedtuple(
'ElementDebugInfo', ('element', 'init_stack', 'attribute_stacks'))
Import
from dm_control.mjcf import debugging
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| --pymjcf_debug flag | bool | No | Command-line flag to enable debug mode (default: False) |
| --pymjcf_debug_full_dump_dir | str | No | Path to dump full debug info when MuJoCo errors are encountered |
| elem | mjcf.Element | Yes (for register) | An MJCF element to register for debugging metadata tracking |
| dump_dir | str | No | Directory path for writing full debug dump files |
Outputs
| Name | Type | Description |
|---|---|---|
| debug_mode() | bool | Whether debug mode is currently enabled |
| get_current_stack_trace() | list[StackTraceEntry] | Current execution stack trace truncated at PyMJCF boundary |
| register_element_for_debugging() | lxml.etree.Comment or None | An XML comment containing debug metadata, or None if debug mode is off |
| commit_xml_string() | str | Reformatted XML string with debug metadata on same line as elements |
Usage Examples
Basic Usage
from dm_control.mjcf import debugging
# Enable debug mode programmatically
debugging.enable_debug_mode()
# Or run with the command-line flag:
# python my_script.py --pymjcf_debug
# Optionally set a dump directory for full debug output
debugging.set_full_dump_dir('/tmp/mjcf_debug')
# When a MuJoCo compile error occurs, the error message will now include
# the Python source location that created the offending MJCF element
# Disable when done
debugging.disable_debug_mode()
Using freeze_current_stack_trace
from dm_control.mjcf import debugging
# Speed up bulk operations in debug mode by caching the stack trace
with debugging.freeze_current_stack_trace():
# All MJCF modifications within this block will share the same
# stack trace, avoiding repeated stack trace construction
for i in range(100):
model.worldbody.add('body', name=f'body_{i}')