microsoft/qlib · error · GymSpaceValidationError
Subspace of index {i} validation error.
Error message
Subspace of index {i} validation error. What it means
Wrapping error from qlib's recursive gym space validator for `spaces.Tuple` (qlib/rl/interpreter.py:127). Element `i` of the sample failed its nested validation and the outer level re-raises with the failing index. The actual cause (bounds/shape/key failure) is preserved in `__cause__`.
Source
Thrown at qlib/rl/interpreter.py:127
raise GymSpaceValidationError("Sample must be a dict with same length as space.", space, x)
for k, subspace in space.spaces.items():
if k not in x:
raise GymSpaceValidationError(f"Key {k} not found in sample.", space, x)
try:
_gym_space_contains(subspace, x[k])
except GymSpaceValidationError as e:
raise GymSpaceValidationError(f"Subspace of key {k} validation error.", space, x) from e
elif isinstance(space, spaces.Tuple):
if isinstance(x, (list, np.ndarray)):
x = tuple(x) # Promote list and ndarray to tuple for contains check
if not isinstance(x, tuple) or len(x) != len(space):
raise GymSpaceValidationError("Sample must be a tuple with same length as space.", space, x)
for i, (subspace, part) in enumerate(zip(space, x)):
try:
_gym_space_contains(subspace, part)
except GymSpaceValidationError as e:
raise GymSpaceValidationError(f"Subspace of index {i} validation error.", space, x) from e
else:
if not space.contains(x):
raise GymSpaceValidationError("Validation error reported by gym.", space, x)
class GymSpaceValidationError(Exception):
def __init__(self, message: str, space: gym.Space, x: Any) -> None:
self.message = message
self.space = space
self.x = x
def __str__(self) -> str:
return f"{self.message}\n Space: {self.space}\n Sample: {self.x}"
View on GitHub (pinned to 79633dd950)
Solutions
- Read `e.__cause__` (or full `str(e)`) to identify the leaf failure and map index `i` back to the interpreter field it corresponds to.
- Clip/normalize that component before returning it from the interpreter (e.g. `np.clip(vol, lo, hi)`).
- Fix the subspace definition if the declared bounds are too tight for legitimate values.
Example fix
// before vols = self.twins_adjust * total # can exceed per-tick bound // after vols = np.clip(self.twins_adjust * total, self._min_vol, self._max_vol)
Defensive patterns
Strategy: try-catch
Validate before calling
for i, (sub, part) in enumerate(zip(space, x)):
assert sub.contains(part), f"element {i}={part!r} not in subspace {sub}" Type guard
def tuple_elements_valid(space: gym.spaces.Tuple, x: tuple) -> bool:
return len(x) == len(space) and all(s.contains(p) for s, p in zip(space, x)) Try / catch
try:
_gym_space_contains(space, x)
except GymSpaceValidationError as e:
idx = parse_index(e.message) # from 'Subspace of index {i} ...'
log.error("component %d failed: %s", idx, e.__cause__)
raise Prevention
- Clip each action component to its subspace bounds in the interpreter.
- Keep component order stable between space definition and action construction.
- Write per-component unit tests so you know which index maps to which semantic field.
When it happens
Trigger: A Tuple space where element `i` violates its subspace: e.g. `spaces.Tuple([Box(0, 1), Box(0, 10)])` with sample `(0.5, 42.0)` — index 1 is out of bounds and this error wraps it.
Common situations: Multi-component action interpreters (e.g. split order into several execution volumes) where one component exceeds its declared range; heterogeneous observations assembled per-step where one field occasionally breaks bounds (NaN in Box, unnormalized price).
Related errors
- Subspace of key {k} validation error.
- Sample must be a tuple with same length as space.
- Key {k} not found in sample.
- Validation error reported by gym.
- Sample must be a dict with same length as space.
AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15).
Data as JSON: /api/errors/67cbb912044e3f25.
Report an issue: GitHub.