microsoft/qlib · error · NotImplementedError

Subclass of FeatureStorage must implement `start_index` meth

Error message

Subclass of FeatureStorage must implement `start_index` method

What it means

FeatureStorage.start_index (qlib/data/storage/storage.py:280) is an abstract property meant to return the left (inclusive) index of the stored data range, or None if the storage is empty. The base class raises NotImplementedError to force concrete backends (FileFeatureStorage, etc.) to define how the first data index is located. Reading `.start_index` on the base class or an incomplete subclass triggers this error.

Source

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

    @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)

            The next  data appending point will be  `end_index + 1`

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

    def clear(self) -> None:
        raise NotImplementedError("Subclass of FeatureStorage must implement `clear` method")

View on GitHub (pinned to 79633dd950)

Solutions

  1. Use a concrete backend like FileFeatureStorage rather than the abstract base
  2. Implement `start_index` in your subclass: return the first index of the stored data, or None if storage does not exist
  3. Ensure any custom storage registered via the storage factory fully implements the FeatureStorage interface (data, start_index, end_index, clear, write)
  4. Audit isinstance checks so abstract instances are rejected before use

Example fix

// before
class MyStorage(FeatureStorage):
    @property
    def data(self):
        return pd.Series(...)
# start_index not overridden -> NotImplementedError

// after
class MyStorage(FeatureStorage):
    @property
    def data(self):
        return pd.Series(...)

    @property
    def start_index(self):
        return None if len(self.data) == 0 else int(self.data.index[0])
Defensive patterns

Strategy: type-guard

Validate before calling

from qlib.data.storage.storage import FeatureStorage
assert type(storage).start_index is not FeatureStorage.start_index, 'start_index not implemented'

Type guard

def has_concrete_start_index(storage) -> bool:
    return type(storage).start_index is not FeatureStorage.start_index

Try / catch

try:
    si = storage.start_index
except NotImplementedError as e:
    raise TypeError(f'{type(storage).__name__} lacks start_index implementation') from e

Prevention

When it happens

Trigger: Accessing `.start_index` on a directly instantiated FeatureStorage; implementing a custom storage backend without overriding the `start_index` property; code paths (e.g. rebase, calendar alignment) that query the range of a storage object that is actually the abstract base.

Common situations: Developing a custom storage backend and only implementing `data`/`write`; refactoring storage code so a factory accidentally returns the base class; testing with a mock that does not subclass correctly.

Related errors


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