{"record":{"id":"2ca2f42b98251794","repo":"microsoft/qlib","slug":"sample-must-be-a-tuple-with-same-length-as-space","errorCode":null,"errorMessage":"Sample must be a tuple with same length as space.","messagePattern":"Sample must be a tuple with same length as space\\.","errorType":"validation","errorClass":"GymSpaceValidationError","httpStatus":null,"severity":"error","filePath":"qlib/rl/interpreter.py","lineNumber":122,"sourceCode":"\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):\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:","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/rl/interpreter.py#L104-L140","documentation":"Raised by qlib's space validator when a `gym.spaces.Tuple` space is validated against a sample that is not a tuple (after list/ndarray promotion) or has a different length than the space (qlib/rl/interpreter.py:122). Note the validator is lenient about types: list and np.ndarray are promoted to tuple; only genuine type/length mismatches fail.","triggerScenarios":"Validating a `spaces.Tuple` space against e.g. an int, a dict, a string, or a list whose length differs from the number of subspaces. Typical in custom ActionInterpreter where the converted action must match a Tuple action space element-for-element.","commonSituations":"Changing the number of sub-actors/twins in an order-execution interpreter without updating the action space; passing a scalar where a 1-element tuple is expected; gym version upgrades changing Tuple internals.","solutions":["Check `len(space)` vs `len(sample)` from the exception's attached `space` and `x` attributes and make lengths equal.","Ensure the interpreter returns a tuple (or list/ndarray) with one element per subspace, in the same order.","Regenerate the Tuple space programmatically from the same config that builds the action so they can't drift."],"exampleFix":"// before\naction_space = spaces.Tuple([spaces.Discrete(2), spaces.Discrete(2)])\nact = (1,)  # wrong length\n// after\naction_space = spaces.Tuple([spaces.Discrete(2), spaces.Discrete(2)])\nact = (1, 0)  # one element per subspace","handlingStrategy":"validation","validationCode":"def validate_tuple_sample(space, x):\n    if isinstance(x, (list,)) : x = tuple(x)\n    assert isinstance(x, tuple), f\"expected tuple, got {type(x)}\"\n    assert len(x) == len(space), f\"len {len(x)} != space len {len(space)}\"","typeGuard":"def matches_tuple_space(space: gym.Space, x: Any) -> bool:\n    if isinstance(space, gym.spaces.Tuple):\n        if isinstance(x, list):\n            x = tuple(x)\n        return isinstance(x, tuple) and len(x) == len(space)\n    return False","tryCatchPattern":"try:\n    _gym_space_contains(action_space, converted_action)\nexcept GymSpaceValidationError as e:\n    raise ValueError(f\"Interpreter produced action not in action space: {e}\") from e","preventionTips":["Build Tuple spaces with a comprehension over the same config that generates the action components.","Return tuples (not scalars) from interpreters even for single-component actions.","Validate converted actions inside ActionInterpreter during development."],"tags":["gym","rl","interpreter","space-validation","tuple"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}