{"record":{"id":"85b165aec748bc5c","repo":"microsoft/qlib","slug":"validation-error-reported-by-gym","errorCode":null,"errorMessage":"Validation error reported by gym.","messagePattern":"Validation error reported by gym\\.","errorType":"validation","errorClass":"GymSpaceValidationError","httpStatus":null,"severity":"error","filePath":"qlib/rl/interpreter.py","lineNumber":131,"sourceCode":"            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):\n    def __init__(self, message: str, space: gym.Space, x: Any) -> None:\n        self.message = message\n        self.space = space\n        self.x = x\n\n    def __str__(self) -> str:\n        return f\"{self.message}\\n  Space: {self.space}\\n  Sample: {self.x}\"\n","sourceCodeStart":113,"sourceCodeEnd":142,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/rl/interpreter.py#L113-L142","documentation":"Leaf-level failure in qlib's space validator (qlib/rl/interpreter.py:131). For any space that is not Dict or Tuple (Box, Discrete, MultiDiscrete, ...), the standard `gym.Space.contains(x)` is used; if gym itself rejects the sample, qlib re-raises it as a GymSpaceValidationError carrying the space and sample for diagnostics.","triggerScenarios":"Validating a Box/Discrete leaf space with an out-of-bounds value, wrong shape, wrong dtype class, or NaN where not allowed. E.g. `spaces.Discrete(3)` with sample `3`, or `spaces.Box(0, 1, shape=(2,))` with sample `np.array([0.5])`.","commonSituations":"Unnormalized observations (prices in thousands against Box(-1,1)); integer vs float dtype confusion under newer gym/numpy versions where `contains` got stricter; NaN leaking from missing market data into a non-NaN-tolerant Box.","solutions":["Use the exception's `space` and `x` attributes to see exactly which value violated which bounds/shape.","Fix the data pipeline: normalize features, forward/backward-fill or drop NaN rows before they reach the interpreter.","Match dtype and shape exactly when constructing samples (e.g. `np.asarray(x, dtype=np.float32).reshape(space.shape)`)."],"exampleFix":"// before\nobs = raw_price_series  # values ~ 1e2..1e4, Box(-1, 1)\n// after\nobs = (raw_price_series - mean) / std  # normalized into Box bounds","handlingStrategy":"validation","validationCode":"import numpy as np\n\ndef check_leaf(space, x):\n    x = np.asarray(x)\n    assert space.contains(x), f\"{x!r} (shape={x.shape}, dtype={x.dtype}) not in {space}\"","typeGuard":"def in_leaf_space(space: gym.Space, x: Any) -> bool:\n    import numpy as np\n    try:\n        return space.contains(np.asarray(x, dtype=getattr(space, 'dtype', None)))\n    except Exception:\n        return False","tryCatchPattern":"try:\n    _gym_space_contains(space, x)\nexcept GymSpaceValidationError as e:\n    if e.message.startswith(\"Validation error reported by gym\"):\n        log.error(\"leaf %r violates space %s\", e.x, e.space)\n    raise","preventionTips":["Normalize all observation features; never feed raw prices into bounded Boxes.","Drop or impute NaN rows before rollout.","Pin gym/numpy versions and re-run space smoke tests after upgrades."],"tags":["gym","rl","interpreter","space-validation","bounds","nan"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}