microsoft/qlib · error · NotImplementedError

Subclass of FeatureStorage must implement `data` method

Error message

Subclass of FeatureStorage must implement `data` method

What it means

qlib's FeatureStorage is an abstract base class (qlib/data/storage/storage.py:270) representing storage for a single feature column (e.g. one instrument's price series). The `data` property is deliberately unimplemented: every concrete storage backend (FileFeatureStorage, ULTRA frequent storage, etc.) must override it to return the full data as a pd.Series. Accessing `.data` on the raw base class, or on a subclass that failed to override it, raises NotImplementedError.

Source

Thrown at qlib/data/storage/storage.py:270

        raise NotImplementedError("Subclass of InstrumentStorage must implement `__len__`  method")


class FeatureStorage(BaseStorage):
    def __init__(self, instrument: str, field: str, freq: str, **kwargs):
        self.instrument = instrument
        self.field = field
        self.freq = freq
        self.kwargs = kwargs

    @property
    def data(self) -> pd.Series:
        """get all data

        Notes
        ------
        if data(storage) does not exist, return empty pd.Series: `return pd.Series(dtype=np.float32)`
        """
        raise NotImplementedError("Subclass of FeatureStorage must implement `data` method")

    @property
    def start_index(self) -> Union[int, None]:
        """get FeatureStorage start index

        Notes
        -----
        If the data(storage) does not exist, return None
        """
        raise NotImplementedError("Subclass of FeatureStorage must implement `start_index` method")

    @property
    def end_index(self) -> Union[int, None]:
        """get FeatureStorage end index

        Notes
        -----
        The  right index of the data range (both sides are closed)

View on GitHub (pinned to 79633dd950)

Solutions

  1. Use a concrete implementation such as qlib.data.storage.file_storage.FileFeatureStorage instead of the base class
  2. If subclassing FeatureStorage yourself, implement the `data` property returning a pd.Series (return pd.Series(dtype=np.float32) when storage does not exist)
  3. Check via qlib.data.storage.storage.get_storage_type / the storage factory that you are receiving a concrete storage instance
  4. Verify no monkey-patching or import shadowing replaces the concrete storage class with the base class

Example fix

// before
storage = FeatureStorage(instrument, field, freq)
series = storage.data  # NotImplementedError

// after
from qlib.data.storage.file_storage import FileFeatureStorage
storage = FileFeatureStorage(instrument, field, freq)
series = storage.data  # pd.Series
Defensive patterns

Strategy: type-guard

Validate before calling

from qlib.data.storage.storage import FeatureStorage
assert not type(storage) is FeatureStorage, 'abstract FeatureStorage cannot be used directly'
assert type(storage).data is not FeatureStorage.data, 'subclass must override `data`'

Type guard

def has_concrete_data(storage) -> bool:
    return hasattr(storage, 'data') and type(storage).data is not FeatureStorage.data

Try / catch

try:
    series = storage.data
except NotImplementedError as e:
    raise TypeError(f'{type(storage).__name__} is not a concrete FeatureStorage backend') from e

Prevention

When it happens

Trigger: Instantiating qlib.data.storage.storage.FeatureStorage (or a custom subclass) directly and reading the `data` property; writing a custom FeatureStorage backend and forgetting to implement the `data` property; a storage factory returning the base class instead of a concrete implementation.

Common situations: Implementing a custom storage backend for a new file format or database; accidentally subclassing the wrong class (e.g. the base FeatureStorage instead of FeatureStorage subclass used by the storage factory); a partially-written backend class during development.

Related errors


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