{"record":{"id":"631b7f4f2fd79f14","repo":"HKUDS/Vibe-Trading","slug":"label-end-times-is-empty","errorCode":null,"errorMessage":"label_end_times is empty","messagePattern":"label_end_times is empty","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/quantlib/crossvalidation.py","lineNumber":133,"sourceCode":"\n    Args:\n        label_end_times: Either a pandas Series whose index is the label start\n            time and whose values are the label end time, or a positional array\n            where element ``i`` is the last positional index observation ``i``'s\n            label depends on.\n        n_samples: Expected number of samples, checked when supplied.\n\n    Returns:\n        Integer array ``ends`` where ``ends[i]`` is the last positional index\n        that observation ``i``'s label covers. Always at least ``i``.\n\n    Raises:\n        ValueError: If the input is empty, not 1-D, holds a non-finite value, or\n            declares a label ending before it starts.\n    \"\"\"\n    if isinstance(label_end_times, pd.Series):\n        if label_end_times.empty:\n            raise ValueError(\"label_end_times is empty\")\n        starts = label_end_times.index\n        ends = label_end_times.to_numpy()\n        # searchsorted on the start index converts label end *times* into label\n        # end *positions*; the right insertion point minus one keeps a label\n        # that ends between two observations attached to the earlier one.\n        positions = np.searchsorted(starts, ends, side=\"right\") - 1\n        positions = np.clip(positions, np.arange(len(starts)), len(starts) - 1)\n        span_ends = positions.astype(int)\n    else:\n        span_ends = np.asarray(label_end_times, dtype=float)\n        if span_ends.ndim != 1:\n            raise ValueError(f\"label_end_times must be 1-D, got shape {span_ends.shape}\")\n        if span_ends.size == 0:\n            raise ValueError(\"label_end_times is empty\")\n        if not np.isfinite(span_ends).all():\n            raise ValueError(\"label_end_times holds a non-finite value\")\n        span_ends = span_ends.astype(int)\n        if (span_ends < np.arange(span_ends.size)).any():","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/quantlib/crossvalidation.py#L115-L151","documentation":"_as_label_spans converts label end times into per-observation span end positions for purged cross-validation. When given a pandas Series, an empty Series means there are no observations/labels to build spans from, so the function refuses immediately rather than producing empty, ambiguous output.","triggerScenarios":"Calling purged_kfold_splits, purged_walk_forward_splits, combinatorial_purged_splits, or detect_boundary_leakage with label_end_times = pd.Series(dtype=object) or an empty pd.Series.","commonSituations":"Empty feature frames after filtering by date or ticker; upstream groupby producing an empty group; loading an empty CSV slice in a walk-forward pipeline.","solutions":["Check `len(label_end_times) > 0` before calling the split functions","Fix the upstream filter/merge that emptied your dataset","Skip empty folds/windows explicitly in your CV loop"],"exampleFix":"# before\nfolds = purged_kfold_splits(pd.Series(dtype=float), n_splits=5)\n\n# after\nends = pd.Series([...non-empty...], index=X.index)\nfolds = purged_kfold_splits(ends, n_splits=5)","handlingStrategy":"validation","validationCode":"if not isinstance(label_end_times, pd.Series) or label_end_times.empty:\n    raise ValueError('label_end_times must be a non-empty pd.Series')\nfolds = purged_kfold_splits(label_end_times, n_splits=5)","typeGuard":"def is_non_empty_series(x) -> bool:\n    return isinstance(x, pd.Series) and not x.empty and x.notna().all()","tryCatchPattern":"try:\n    folds = purged_kfold_splits(ends, n_splits=5)\nexcept ValueError as e:\n    if 'empty' in str(e):\n        logger.warning('empty fold window skipped')\n        folds = []\n    else:\n        raise","preventionTips":["Assert a minimum row count before running CV","Log dataset size at each CV boundary to catch empty windows","Skip empty groups explicitly in walk-forward loops"],"tags":["cross-validation","purged-kfold","pandas","empty-input","python"],"backgroundTag":"empty-array-argument","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}