microsoft/qlib · error · TypeError

stock selector must be type str|list, or slice(None), rather

Error message

stock selector must be type str|list, or slice(None), rather than {stock_selector}

What it means

Raised by the storage selector parser (qlib/data/dataset/storage.py) after extracting the stock selector: the final value must be a str, a list, or slice(None). Any other type (int, dict, None, numpy array, tuple, pd.Index) fails this check with a TypeError. It is the last line of defense normalizing instrument selectors before they are used to filter the hash_df of instruments.

Source

Thrown at qlib/data/dataset/storage.py:154

            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]
        return select_dict, time_selector

    def fetch(
        self,
        selector: Union[pd.Timestamp, slice, str, pd.Index] = slice(None, None),
        level: Union[str, int] = "datetime",
        col_set: Union[str, List[str]] = DataHandler.CS_ALL,

View on GitHub (pinned to 79633dd950)

Solutions

  1. Convert the selector to a list of instrument-code strings: selector = list(pd_index) or selector = arr.tolist().
  2. Wrap a single code in a string or list: "SH600000" or ["SH600000"], never a one-element tuple.
  3. Use slice(None) explicitly when you want all instruments.
  4. Check that the selector variable is actually set (not None) before calling the API.

Example fix

# before
storage.select(np.array(["SH600000", "SZ000001"]), level="instrument")

# after
codes = np.array(["SH600000", "SZ000001"]).tolist()
storage.select(codes, level="instrument")
Defensive patterns

Strategy: type-guard

Validate before calling

if not isinstance(selector, (str, list)) and selector != slice(None):
    selector = list(selector)  # accept pd.Index / np.array / iterable

Type guard

def is_stock_selector(s) -> bool:
    return isinstance(s, (str, list)) or s == slice(None)

Try / catch

try:
    storage.select(selector, level="instrument")
except TypeError as e:
    if "stock selector" in str(e):
        storage.select(list(selector), level="instrument")
    else:
        raise

Prevention

When it happens

Trigger: Calling the instrument-level selection API with selector=0, selector=None, selector=np.array([...]), selector=('SH600000',), or a dict. Also triggered when a selector variable is unset and defaults to None.

Common situations: Programmatically building selectors and passing a pandas Index or numpy array instead of converting to list; forwarding an unprocessed user argument into low-level storage APIs; None leaking in from a missing config value.

Related errors


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