{"record":{"id":"d5d00c71859233f1","repo":"microsoft/qlib","slug":"subspace-of-key-k-validation-error","errorCode":null,"errorMessage":"Subspace of key {k} validation error.","messagePattern":"Subspace of key (.+?) validation error\\.","errorType":"validation","errorClass":"GymSpaceValidationError","httpStatus":null,"severity":"error","filePath":"qlib/rl/interpreter.py","lineNumber":116,"sourceCode":"        raise NotImplementedError(\"interpret is not implemented!\")\n\n\ndef _gym_space_contains(space: gym.Space, x: Any) -> None:\n    \"\"\"Strengthened version of gym.Space.contains.\n    Giving more diagnostic information on why validation fails.\n\n    Throw exception rather than returning true or false.\n    \"\"\"\n    if isinstance(space, spaces.Dict):\n        if not isinstance(x, dict) or len(x) != len(space):\n            raise GymSpaceValidationError(\"Sample must be a dict with same length as space.\", space, x)\n        for k, subspace in space.spaces.items():\n            if k not in x:\n                raise GymSpaceValidationError(f\"Key {k} not found in sample.\", space, x)\n            try:\n                _gym_space_contains(subspace, x[k])\n            except GymSpaceValidationError as e:\n                raise GymSpaceValidationError(f\"Subspace of key {k} validation error.\", space, x) from e\n\n    elif isinstance(space, spaces.Tuple):\n        if isinstance(x, (list, np.ndarray)):\n            x = tuple(x)  # Promote list and ndarray to tuple for contains check\n        if not isinstance(x, tuple) or len(x) != len(space):\n            raise GymSpaceValidationError(\"Sample must be a tuple with same length as space.\", space, x)\n        for i, (subspace, part) in enumerate(zip(space, x)):\n            try:\n                _gym_space_contains(subspace, part)\n            except GymSpaceValidationError as e:\n                raise GymSpaceValidationError(f\"Subspace of index {i} validation error.\", space, x) from e\n\n    else:\n        if not space.contains(x):\n            raise GymSpaceValidationError(\"Validation error reported by gym.\", space, x)\n\n\nclass GymSpaceValidationError(Exception):","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/rl/interpreter.py#L98-L134","documentation":"Wrapping error from qlib's recursive gym space validator (qlib/rl/interpreter.py:116). It is raised only as a re-raise: the sub-value `x[k]` of a Dict space failed validation in a nested call to `_gym_space_contains`, and the outer call decorates the original error with the offending key. The true root cause is in the exception chain (`__cause__`), not this message.","triggerScenarios":"A `spaces.Dict` space whose value for key `k` is itself a Dict/Tuple/Box, and `x[k]` fails the nested check: wrong length tuple, out-of-bounds Box value, missing nested key, etc. Example: `spaces.Dict({\"obs\": spaces.Box(-1, 1)})` with `x[\"obs\"] = 2.5`.","commonSituations":"Nested observation spaces in custom order-execution interpreters; actions outside the declared action Box (e.g. interpreter yields >1 for a Box(-1,1) action space); dtype mismatches inside nested structures.","solutions":["Inspect the chained exception (`except GymSpaceValidationError as e: print(e.__cause__)`) to find the leaf-level failure and which key path led there.","Fix the leaf value: clamp/normalize the action or observation so it satisfies the inner space's bounds/shape.","If the inner space bounds are wrong, widen or re-derive `action_space`/`observation_space` in your interpreter."],"exampleFix":"// before\naction_space = spaces.Box(-1.0, 1.0, shape=(1,))\nact = np.array([1.7])  # out of bounds -> nested validation fails, wrapped as 'Subspace of key ...'\n// after\nact = np.clip(raw_act, -1.0, 1.0)  # satisfy inner Box bounds","handlingStrategy":"try-catch","validationCode":"from qlib.rl.interpreter import _gym_space_contains\n_gym_space_contains(space, sample)  # run in tests before starting training","typeGuard":"def leaf_in_bounds(box: gym.spaces.Box, v) -> bool:\n    import numpy as np\n    v = np.asarray(v, dtype=box.dtype)\n    return v.shape == box.shape and (v >= box.low).all() and (v <= box.high).all()","tryCatchPattern":"try:\n    _gym_space_contains(space, x)\nexcept GymSpaceValidationError as e:\n    cause = e.__cause__ or e\n    log.error(\"key-path failure: %s | root cause: %s\", e.message, cause)\n    raise","preventionTips":["Always log e.__cause__, not just the wrapper message, to reach the leaf failure.","Clamp/normalize observations and actions at the interpreter boundary.","Add a smoke rollout (a few env steps) to CI so nested space mismatches fail early."],"tags":["gym","rl","interpreter","space-validation","nested","exception-chaining"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}