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

  1. Pass the instrument selector directly (a string or list of instrument codes), not a tuple: use "SH600000" or ["SH600000"] instead of ("SH600000", ...).
  2. 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.
  3. 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

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


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