microsoft/qlib · error · IndexError

{i}: start index is {storage_start_index}

Error message

{i}: start index is {storage_start_index}

What it means

Raised by FileFeatureStorage.__getitem__ (qlib/data/storage/file_storage.py) when an integer index i is smaller than the storage's start_index. Bin files only cover rows [start_index, end_index]; querying an index before the first stored row cannot be answered, so an IndexError names the requested index and the actual start index. Slices, by contrast, are clamped to the available range and never raise.

Source

Thrown at qlib/data/storage/file_storage.py:360

            return None
        # The next  data appending index point will be  `end_index + 1`
        return self.start_index + len(self) - 1

    def __getitem__(self, i: Union[int, slice]) -> Union[Tuple[int, float], pd.Series]:
        if not self.uri.exists():
            if isinstance(i, int):
                return None, None
            elif isinstance(i, slice):
                return pd.Series(dtype=np.float32)
            else:
                raise TypeError(f"type(i) = {type(i)}")

        storage_start_index = self.start_index
        storage_end_index = self.end_index
        with self.uri.open("rb") as fp:
            if isinstance(i, int):
                if storage_start_index > i:
                    raise IndexError(f"{i}: start index is {storage_start_index}")
                fp.seek(4 * (i - storage_start_index) + 4)
                return i, struct.unpack("f", fp.read(4))[0]
            elif isinstance(i, slice):
                start_index = storage_start_index if i.start is None else i.start
                end_index = storage_end_index if i.stop is None else i.stop - 1
                si = max(start_index, storage_start_index)
                if si > end_index:
                    return pd.Series(dtype=np.float32)
                fp.seek(4 * (si - storage_start_index) + 4)
                # read n bytes
                count = end_index - si + 1
                data = np.frombuffer(fp.read(4 * count), dtype="<f")
                return pd.Series(data, index=pd.RangeIndex(si, si + len(data)))
            else:
                raise TypeError(f"type(i) = {type(i)}")

    def __len__(self) -> int:
        self.check()

View on GitHub (pinned to 79633dd950)

Solutions

  1. Query per-instrument ranges: use storage.start_index / storage.end_index to clamp, or use slice-based access which clamps automatically.
  2. Prefer qlib's expression/data APIs (D.features, Cal.calendar) over raw storage indexing; they handle per-instrument coverage.
  3. If the data should exist that far back, re-dump the instrument's bin file with a longer history.

Example fix

# before
first = feature_storage[calendar_index]  # calendar_index < storage.start_index -> IndexError

# after
start = feature_storage.start_index
first = feature_storage[max(calendar_index, start)]
# or simply use a slice, which clamps:
first = feature_storage[calendar_index:calendar_index + 1]
Defensive patterns

Strategy: validation

Validate before calling

i = max(int(i), storage.start_index)
if i > storage.end_index:
    i = storage.start_index  # or handle 'no data' explicitly

Type guard

def index_within_storage(i: int, storage) -> bool:
    return storage.start_index <= i <= storage.end_index

Try / catch

try:
    _, val = storage[i]
except IndexError as e:
    if "start index is" in str(e):
        _, val = storage[storage.start_index]  # clamp to first available row
    else:
        raise

Prevention

When it happens

Trigger: feature_storage[1234] when that instrument's bin file starts at start_index=1500 (e.g. the stock listed later than the requested calendar position). Common when computing calendar-relative indices for an instrument whose data begins mid-calendar.

Common situations: Hand-computing absolute calendar indices and applying them to every instrument equally; early-listed vs late-listed instruments in a cross-section; code that assumes all bin files start at the same index.

Related errors


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