microsoft/qlib · error · TypeError

Expected `tuple` type, but got a value `{key}`

Error message

Expected `tuple` type, but got a value `{key}`

What it means

RollingGroup (qlib/model/ens/group.py:111) groups the output of a rolling ensemble, whose keys are expected to be tuples like (model_key, ..., rolling_tag): it strips the last element as the rolling key. If a key in the passed dict is not a tuple (contrary to the documented contract 'If the key is not a tuple, then do nothing' — the code actually raises), it raises TypeError with the offending key.

Source

Thrown at qlib/model/ens/group.py:111

    """Group the rolling dict"""

    def group(self, rolling_dict: dict) -> dict:
        """Given an rolling dict likes {(A,B,R): things}, return the grouped dict likes {(A,B): {R:things}}

        NOTE: There is an assumption which is the rolling key is at the end of the key tuple, because the rolling results always need to be ensemble firstly.

        Args:
            rolling_dict (dict): an rolling dict. If the key is not a tuple, then do nothing.

        Returns:
            dict: grouped dict
        """
        grouped_dict = {}
        for key, values in rolling_dict.items():
            if isinstance(key, tuple):
                grouped_dict.setdefault(key[:-1], {})[key[-1]] = values
            else:
                raise TypeError(f"Expected `tuple` type, but got a value `{key}`")
        return grouped_dict

    def __init__(self, ens=RollingEnsemble()):
        super().__init__(ens=ens)

View on GitHub (pinned to 79633dd950)

Solutions

  1. Build the dict with tuple keys whose last element is the rolling tag, e.g. {(model_key, rolling_tag): model}
  2. Use RollingEnsemble's own output as input to RollingGroup.group to guarantee key shape
  3. If you actually have plain string keys, use the plain Ensemble/Group classes instead of RollingGroup
  4. Inspect dict keys before grouping and reject/convert non-tuple keys explicitly

Example fix

# before
rolling_dict = {'lgb_model': m1, 'xgb_model': m2}
RollingGroup().group(rolling_dict)  # TypeError

# after
rolling_dict = {('lgb_model', 'roll_1'): m1, ('xgb_model', 'roll_1'): m2}
RollingGroup().group(rolling_dict)
Defensive patterns

Strategy: type-guard

Validate before calling

bad = [k for k in rolling_dict if not isinstance(k, tuple)]
assert not bad, f'non-tuple keys not allowed for RollingGroup: {bad}'

Type guard

def is_rolling_dict(d: dict) -> bool:
    return all(isinstance(k, tuple) and len(k) >= 2 for k in d)

Try / catch

try:
    grouped = RollingGroup().group(rolling_dict)
except TypeError as e:
    raise ValueError('use tuple keys (model_key, ..., rolling_tag)') from e

Prevention

When it happens

Trigger: Calling RollingGroup.group(rolling_dict) with a dict whose keys are plain strings or other non-tuple values instead of tuples ending with the rolling tag; feeding a model dict produced outside the RollingEnsemble workflow (e.g. {model_key: model} instead of {(model_key, rolling): model}).

Common situations: Manually assembling ensemble inputs for rolling models; mixing ensemble outputs from RollingEnsemble (tuple keys) with plain Ensemble (string keys); refactors that change dict key structure.

Related errors


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