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
- Build the dict with tuple keys whose last element is the rolling tag, e.g. {(model_key, rolling_tag): model}
- Use RollingEnsemble's own output as input to RollingGroup.group to guarantee key shape
- If you actually have plain string keys, use the plain Ensemble/Group classes instead of RollingGroup
- 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
- Always consume RollingEnsemble output as RollingGroup input to preserve tuple keys
- Document the expected key shape at ensemble construction sites
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
- This type of `limit_threshold` is not supported
- stock data from resam_ts_data must be a number, pd.Series or
- provider_uri does not support {type(provider_uri)}
- This type of input is not supported
- astype not supported: {astype}
AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15).
Data as JSON: /api/errors/287aebc1acde6bbc.
Report an issue: GitHub.