HKUDS/Vibe-Trading · error · ValueError
label_end_times holds a non-finite value
Error message
label_end_times holds a non-finite value
What it means
_as_label_spans casts array-based label_end_times to float then int positions; NaN or inf values would silently cast to garbage integers (e.g. NaN -> platform-dependent int), corrupting every purge decision. All values are therefore required to be finite.
Source
Thrown at agent/src/quantlib/crossvalidation.py:149
if isinstance(label_end_times, pd.Series):
if label_end_times.empty:
raise ValueError("label_end_times is empty")
starts = label_end_times.index
ends = label_end_times.to_numpy()
# searchsorted on the start index converts label end *times* into label
# end *positions*; the right insertion point minus one keeps a label
# that ends between two observations attached to the earlier one.
positions = np.searchsorted(starts, ends, side="right") - 1
positions = np.clip(positions, np.arange(len(starts)), len(starts) - 1)
span_ends = positions.astype(int)
else:
span_ends = np.asarray(label_end_times, dtype=float)
if span_ends.ndim != 1:
raise ValueError(f"label_end_times must be 1-D, got shape {span_ends.shape}")
if span_ends.size == 0:
raise ValueError("label_end_times is empty")
if not np.isfinite(span_ends).all():
raise ValueError("label_end_times holds a non-finite value")
span_ends = span_ends.astype(int)
if (span_ends < np.arange(span_ends.size)).any():
raise ValueError(
"a label cannot end before the observation it belongs to starts"
)
if n_samples is not None and span_ends.size != n_samples:
raise ValueError(
f"label_end_times has {span_ends.size} entries but the sample has {n_samples}"
)
return span_ends
def _apply_purge_and_embargo(
label_ends: np.ndarray,
test_mask: np.ndarray,
embargo_size: int,
) -> tuple[np.ndarray, int, int]:View on GitHub (pinned to 80ffdda44c)
Solutions
- Drop or fill non-finite entries first: ends = ends[np.isfinite(ends)] or use fillna before calling
- Fix the merge/reindex that introduced NaNs by aligning on observation ids
- Add an assertion np.isfinite(ends).all() in your data pipeline
Example fix
# before folds = purged_kfold_splits(np.array([2.0, np.nan, 5.0]), n_splits=2) # after ends = np.nan_to_num(np.array([2.0, np.nan, 5.0]), nan=3.0) folds = purged_kfold_splits(ends, n_splits=2)
Defensive patterns
Strategy: validation
Validate before calling
ends = np.asarray(label_end_times, dtype=float)
if not np.isfinite(ends).all():
bad = np.where(~np.isfinite(ends))[0]
raise ValueError(f'non-finite label end times at positions {bad}')
folds = purged_kfold_splits(ends, n_splits=5) Type guard
def all_finite(x) -> bool:
return bool(np.isfinite(np.asarray(x, dtype=float)).all()) Try / catch
try:
folds = purged_kfold_splits(ends, n_splits=5)
except ValueError as e:
if 'non-finite' in str(e):
ends = ends[np.isfinite(ends)]
folds = purged_kfold_splits(ends, n_splits=5)
else:
raise Prevention
- Run np.isfinite checks right after merges/reindexes that can inject NaN
- Drop rows with missing label horizons before feature engineering
- Avoid sentinel values like -999/inf in label-end columns
When it happens
Trigger: Passing an array containing np.nan, np.inf, or -inf as label end positions, e.g. from a merge that introduced NaNs or an unfilled mask.
Common situations: NaNs introduced by left joins or reindexing on misaligned indexes; sentinel values like -999 replaced later but not here; inf from division by zero when computing end positions.
Related errors
- label_end_times must be 1-D, got shape {span_ends.shape}
- amount must be a finite number, got {self.amount!r}; a missi
- survival_prob must be in (0.0, 1.0], got {survival_prob}
- tenor_years must be strictly positive, got {tenor_years}
- spread_bps must be non-negative, got {spread_bps}
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/fa24a874d7e59786.
Report an issue: GitHub.