microsoft/qlib · error · GymSpaceValidationError
Key {k} not found in sample.
Error message
Key {k} not found in sample. What it means
Raised by qlib's strengthened gym space validator `_gym_space_contains` (qlib/rl/interpreter.py:112). When a sample is validated against a `gym.spaces.Dict` space, every key present in `space.spaces` must also exist in the sample dict. If a key `k` defined by the space is missing from `x`, this GymSpaceValidationError is thrown with full diagnostics (space and sample are attached to the exception).
Source
Thrown at qlib/rl/interpreter.py:112
Returns
-------
The action needed by simulator,
"""
raise NotImplementedError("interpret is not implemented!")
def _gym_space_contains(space: gym.Space, x: Any) -> None:
"""Strengthened version of gym.Space.contains.
Giving more diagnostic information on why validation fails.
Throw exception rather than returning true or false.
"""
if isinstance(space, spaces.Dict):
if not isinstance(x, dict) or len(x) != len(space):
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):View on GitHub (pinned to 79633dd950)
Solutions
- Print the exception: `str(e)` shows both the expected space and the offending sample; add the missing key to the sample dict.
- Align your interpreter's `observation_space(...)` return value with the keys actually produced in `state_interpreter.simulator_state` -> observation conversion.
- If the key is genuinely optional, model it with a Tuple/Dict structure that matches, or always emit the key (possibly NaN-filled).
- Write a unit test that calls `_gym_space_contains(interpreter.observation_space, sample)` on real simulator output.
Example fix
// before
obs_space = spaces.Dict({"position": spaces.Box(...), "history": spaces.Box(...)})
sample = {"position": pos} # missing "history"
// after
obs_space = spaces.Dict({"position": spaces.Box(...), "history": spaces.Box(...)})
sample = {"position": pos, "history": hist} # all keys present Defensive patterns
Strategy: validation
Validate before calling
from qlib.rl.interpreter import _gym_space_contains
def validate_sample(space, sample):
assert isinstance(sample, dict), "sample must be dict for Dict space"
missing = set(space.spaces.keys()) - set(sample.keys())
extra = set(sample.keys()) - set(space.spaces.keys())
assert not missing, f"sample missing keys: {missing}"
assert not extra, f"sample has extra keys: {extra}"
_gym_space_contains(space, sample) # deep check before running the env Type guard
def matches_dict_space(space: gym.Space, x: Any) -> bool:
return (
isinstance(space, gym.spaces.Dict)
and isinstance(x, dict)
and len(x) == len(space.spaces)
and set(x.keys()) == set(space.spaces.keys())
) Try / catch
try:
_gym_space_contains(obs_space, sample)
except GymSpaceValidationError as e:
raise RuntimeError(f"Bad observation for space: {e}") from e Prevention
- Derive the Dict space and the sample from the same source of truth (same keys list) in your interpreter.
- Unit-test interpreter output against interpreter.observation_space on real simulator states.
- Never hand-write observation dicts in tests; always call the state interpreter.
When it happens
Trigger: Calling an interpreter whose observation/action space is a `spaces.Dict` with a sample dict that lacks one of the declared keys (e.g. building an observation manually, or a StateInterpreter whose `observation_space` declares keys the simulator state does not emit). Also triggered when len(x) matches but keys are renamed or mis-typed (e.g. 'position' vs 'Position').
Common situations: Custom RL interpreters where `observation_space` was copy-pasted from another interpreter; gym version changes that alter Dict space representation; tests that hand-craft observations instead of running the simulator.
Related errors
- Subspace of key {k} validation error.
- Sample must be a tuple with same length as space.
- Subspace of index {i} validation error.
- 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/2e85f4da7fc2e19b.
Report an issue: GitHub.