#3236·IsaacLab

[Bug Report] `update_class_from_dict` does not handle union types properly

Author: pculbertsonCreated Aug 20, 2025Updated Sep 17, 2026
Labelsbug

Describe the bug

When calling update_class_from_dict, it introspects using the type currently stored in the configclass. This will raise a ValueError for fields annotated as union types (e.g., int | None) where the override value is of the other type.

Steps to reproduce

Run the following MRE:

from isaaclab.app import AppLauncher


if __name__ == "__main__":
    app_launcher = AppLauncher(
        headless=True, kit_args="--no-window", enable_cameras=False
    )

    from isaaclab.utils import configclass

    @configclass
    class TestConfig:
        param: int | None = None

    config = TestConfig()
    config.from_dict({"param": 42})  # Raises ValueError

This raises ValueError: [Config]: Incorrect type under namespace: /param. Expected: <class 'NoneType'>, Received: <class 'int'>, despite param being annotated as allowing values of type int.

The issue is this line, which checks the new value's type against the value currently stored in the field, instead of its annotation.

I'll also note that it's unclear why this explicit check is needed since configclass.validate() also checks explicitly each value against its type annotation.

System Info

Describe the characteristic of your environment:

  • Commit: 46dff13 (v2.2.0)
  • Isaac Sim Version: 5.0
  • OS: Ubuntu 22.04 LTS
  • GPU: Tesla T4
  • CUDA: 12.8
  • GPU Driver: 550.54.15

Additional context

In practice I'm hitting this issue when trying to pass overrides to a ManagerBasedRLEnvCfg - since seed defaults to None, I cannot replace it with an int.

Checklist

  • I have checked that there is no similar issue in the repo (required)
  • I have checked that the issue is not in running Isaac Sim itself and is related to the repo

Acceptance Criteria

Add the criteria for which this task is considered done. If not known at issue creation time, you can add this once the issue is assigned.

  • The MRE above runs without raising a ValueError