microsoft/qlib · error · TypeError
I forget why would this case appear. But I think it does not
Error message
I forget why would this case appear. But I think it does not make sense. So we raise a error for that case.
What it means
A defensive TypeError in UCData/storage selector parsing (qlib/data/dataset/storage.py). When selecting at the instrument level, a selector of type tuple is considered nonsensical: the code assigns stock_selector = selector[0] and then immediately raises, with an apologetic message ('I forget why would this case appear...'). In practice this branch is unreachable defensive code guarding against unexpected selector shapes reaching the instrument level.
Source
Thrown at qlib/data/dataset/storage.py:147
"""
stock_selector = slice(None)
time_selector = slice(None) # by default not filter by time.
if level is None:
# For directly applying.
if isinstance(selector, tuple) and self.stock_level < len(selector):
# full selector format
stock_selector = selector[self.stock_level]
time_selector = selector[1 - self.stock_level]
elif isinstance(selector, (list, str)) and self.stock_level == 0:
# only stock selector
stock_selector = selector
elif level in ("instrument", self.stock_level):
if isinstance(selector, tuple):
# NOTE: How could the stock level selector be a tuple?
stock_selector = selector[0]
raise TypeError(
"I forget why would this case appear. But I think it does not make sense. So we raise a error for that case."
)
elif isinstance(selector, (list, str)):
stock_selector = selector
if not isinstance(stock_selector, (list, str)) and stock_selector != slice(None):
raise TypeError(f"stock selector must be type str|list, or slice(None), rather than {stock_selector}")
if stock_selector == slice(None):
return self.hash_df, time_selector
if isinstance(stock_selector, str):
stock_selector = [stock_selector]
select_dict = dict()
for each_stock in sorted(stock_selector):
if each_stock in self.hash_df:
select_dict[each_stock] = self.hash_df[each_stock]View on GitHub (pinned to 79633dd950)
Solutions
- Pass the instrument selector directly (a string or list of instrument codes), not a tuple: use "SH600000" or ["SH600000"] instead of ("SH600000", ...).
- If you need both stock and time selection, call the API that accepts a full tuple selector with level="multi_index" or per the storage's documented selector format.
- If you genuinely believe a tuple is valid here, report upstream — the source comment itself says the authors were unsure this case can occur.
Example fix
// before (conceptual)
storage.get_selector(selector=("SH600000", slice(None)), level="instrument")
// after
storage.get_selector(selector="SH600000", level="instrument") Defensive patterns
Strategy: type-guard
Validate before calling
assert not isinstance(selector, tuple), "instrument-level selector must not be a tuple; pass str or list"
Type guard
def is_instrument_selector(s) -> bool:
return isinstance(s, (str, list)) or s == slice(None) Prevention
- Pass only str/list at instrument level; reserve tuple selectors for multi-level APIs.
- Wrap storage access behind your own helper that normalizes selectors once.
When it happens
Trigger: Calling the storage's selector-normalization path with level in ("instrument", stock_level) and a tuple selector, e.g. data[('SH600000', slice(None))] where the API expects level="instrument" to receive a plain list/str. Only reachable through internal APIs that pass raw user selectors down to this method.
Common situations: Passing a (stock, time) tuple selector to a method that only expects an instrument selector at that level; misuse of low-level storage APIs instead of the public Series/DataFrame interfaces. End users of qlib's public APIs rarely hit this; it mainly guards internal invariants.
Related errors
- stock selector must be type str|list, or slice(None), rather
- Invalid mount path
- direction not supported, `Order.SELL` for sell, `Order.BUY`
- {self.storage_name}: {self.provider_uri} does not contain da
- {self.storage_name} not exists: {self.uri}
AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15).
Data as JSON: /api/errors/d1d1ac2a00884bd7.
Report an issue: GitHub.