microsoft/qlib · error · GymSpaceValidationError

Sample must be a tuple with same length as space.

Error message

Sample must be a tuple with same length as space.

What it means

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.

Source

Thrown at qlib/rl/interpreter.py:122

    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):
            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:

View on GitHub (pinned to 79633dd950)

Solutions

  1. Check `len(space)` vs `len(sample)` from the exception's attached `space` and `x` attributes and make lengths equal.
  2. Ensure the interpreter returns a tuple (or list/ndarray) with one element per subspace, in the same order.
  3. Regenerate the Tuple space programmatically from the same config that builds the action so they can't drift.

Example fix

// before
action_space = spaces.Tuple([spaces.Discrete(2), spaces.Discrete(2)])
act = (1,)  # wrong length
// after
action_space = spaces.Tuple([spaces.Discrete(2), spaces.Discrete(2)])
act = (1, 0)  # one element per subspace
Defensive patterns

Strategy: validation

Validate before calling

def validate_tuple_sample(space, x):
    if isinstance(x, (list,)) : x = tuple(x)
    assert isinstance(x, tuple), f"expected tuple, got {type(x)}"
    assert len(x) == len(space), f"len {len(x)} != space len {len(space)}"

Type guard

def matches_tuple_space(space: gym.Space, x: Any) -> bool:
    if isinstance(space, gym.spaces.Tuple):
        if isinstance(x, list):
            x = tuple(x)
        return isinstance(x, tuple) and len(x) == len(space)
    return False

Try / catch

try:
    _gym_space_contains(action_space, converted_action)
except GymSpaceValidationError as e:
    raise ValueError(f"Interpreter produced action not in action space: {e}") from e

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15). Data as JSON: /api/errors/2ca2f42b98251794. Report an issue: GitHub.