microsoft/qlib · error · ValueError

Unsupported input type for param `instrument`

Error message

Unsupported input type for param `instrument`

What it means

`Cal.calendar`-side sibling check in `Inst.get_instruments_d`: the `instruments` parameter of dataset/D.features calls must be either a dict (stockpool config if it has key 'market', else an {instrument: (start,end)} dict) or a list/tuple/pd.Index/np.ndarray. Any other type raises this ValueError before data loading starts.

Source

Thrown at qlib/data/data.py:528

    @staticmethod
    def get_instruments_d(instruments, freq):
        """
        Parse different types of input instruments to output instruments_d
        Wrong format of input instruments will lead to exception.

        """
        if isinstance(instruments, dict):
            if "market" in instruments:
                # dict of stockpool config
                instruments_d = Inst.list_instruments(instruments=instruments, freq=freq, as_list=False)
            else:
                # dict of instruments and timestamp
                instruments_d = instruments
        elif isinstance(instruments, (list, tuple, pd.Index, np.ndarray)):
            # list or tuple of a group of instruments
            instruments_d = list(instruments)
        else:
            raise ValueError("Unsupported input type for param `instrument`")
        return instruments_d

    @staticmethod
    def get_column_names(fields):
        """
        Get column names from input fields

        """
        if len(fields) == 0:
            raise ValueError("fields cannot be empty")
        column_names = [str(f) for f in fields]
        return column_names

    @staticmethod
    def parse_fields(fields):
        # parse and check the input fields
        return [ExpressionD.get_expression_instance(f) for f in fields]

View on GitHub (pinned to 79633dd950)

Solutions

  1. Wrap the string: `D.features(instruments={'market': 'csi300'}, ...)` or `instruments=D.instruments('csi300')`.
  2. Convert sets: `instruments=list(my_set)`.
  3. For per-instrument time ranges, use `{'SH600000': ('2015-01-01', '2020-12-31')}`.

Example fix

# before
df = D.features('csi300', ['$close'], start_time='2020-01-01', end_time='2020-12-31')

# after
df = D.features({'market': 'csi300'}, ['$close'], start_time='2020-01-01', end_time='2020-12-31')
Defensive patterns

Strategy: type-guard

Validate before calling

import pandas as pd, numpy as np

def normalize_instruments(inst):
    if isinstance(inst, str):
        return {'market': inst}          # 'csi300' -> market config
    if isinstance(inst, set):
        return list(inst)
    assert isinstance(inst, (dict, list, tuple, pd.Index, np.ndarray)), 'bad instruments type'
    return inst

Type guard

import pandas as pd, np

def is_supported_instruments(inst) -> bool:
    return isinstance(inst, (dict, list, tuple, pd.Index, np.ndarray))

Prevention

When it happens

Trigger: Calling `D.features(instruments='csi300', ...)` or `DatasetH(instruments='all', ...)` with a bare string/None/int. Same shape rules as get_inst_type but a different error site.

Common situations: Passing market names as plain strings into DatasetH/D.features; passing a set of instruments (not accepted); passing None after a config-processing bug.

Related errors


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