{"record":{"id":"2e85f4da7fc2e19b","repo":"microsoft/qlib","slug":"key-k-not-found-in-sample","errorCode":null,"errorMessage":"Key {k} not found in sample.","messagePattern":"Key (.+?) not found in sample\\.","errorType":"validation","errorClass":"GymSpaceValidationError","httpStatus":null,"severity":"error","filePath":"qlib/rl/interpreter.py","lineNumber":112,"sourceCode":"        Returns\n        -------\n        The action needed by simulator,\n        \"\"\"\n        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):","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/rl/interpreter.py#L94-L130","documentation":"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).","triggerScenarios":"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').","commonSituations":"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.","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."],"exampleFix":"// before\nobs_space = spaces.Dict({\"position\": spaces.Box(...), \"history\": spaces.Box(...)})\nsample = {\"position\": pos}  # missing \"history\"\n// after\nobs_space = spaces.Dict({\"position\": spaces.Box(...), \"history\": spaces.Box(...)})\nsample = {\"position\": pos, \"history\": hist}  # all keys present","handlingStrategy":"validation","validationCode":"from qlib.rl.interpreter import _gym_space_contains\n\ndef validate_sample(space, sample):\n    assert isinstance(sample, dict), \"sample must be dict for Dict space\"\n    missing = set(space.spaces.keys()) - set(sample.keys())\n    extra = set(sample.keys()) - set(space.spaces.keys())\n    assert not missing, f\"sample missing keys: {missing}\"\n    assert not extra, f\"sample has extra keys: {extra}\"\n    _gym_space_contains(space, sample)  # deep check before running the env","typeGuard":"def matches_dict_space(space: gym.Space, x: Any) -> bool:\n    return (\n        isinstance(space, gym.spaces.Dict)\n        and isinstance(x, dict)\n        and len(x) == len(space.spaces)\n        and set(x.keys()) == set(space.spaces.keys())\n    )","tryCatchPattern":"try:\n    _gym_space_contains(obs_space, sample)\nexcept GymSpaceValidationError as e:\n    raise RuntimeError(f\"Bad observation for space: {e}\") from e","preventionTips":["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."],"tags":["gym","rl","interpreter","space-validation","dict"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}