microsoft/qlib · critical · ValueError

Empty data from dataset, please check your dataset config.

Error message

Empty data from dataset, please check your dataset config.

What it means

GATsTSModel.fit() prepares the 'train' and 'valid' segments as time-series dataloaders and raises ValueError if either is empty, before any DailyBatchSampler or DataLoader is built. The ts variant slices fixed-length history windows, so an empty segment can also result from a valid range shorter than the step/history length even when raw data exists.

Source

Thrown at qlib/contrib/model/pytorch_gats_ts.py:242

            pred = self.GAT_model(feature.float())
            loss = self.loss_fn(pred, label)
            losses.append(loss.item())

            score = self.metric_fn(pred, label)
            scores.append(score.item())

        return np.mean(losses), np.mean(scores)

    def fit(
        self,
        dataset,
        evals_result=dict(),
        save_path=None,
    ):
        dl_train = dataset.prepare("train", col_set=["feature", "label"], data_key=DataHandlerLP.DK_L)
        dl_valid = dataset.prepare("valid", col_set=["feature", "label"], data_key=DataHandlerLP.DK_L)
        if dl_train.empty or dl_valid.empty:
            raise ValueError("Empty data from dataset, please check your dataset config.")

        dl_train.config(fillna_type="ffill+bfill")  # process nan brought by dataloader
        dl_valid.config(fillna_type="ffill+bfill")  # process nan brought by dataloader

        sampler_train = DailyBatchSampler(dl_train)
        sampler_valid = DailyBatchSampler(dl_valid)

        train_loader = DataLoader(dl_train, sampler=sampler_train, num_workers=self.n_jobs, drop_last=True)
        valid_loader = DataLoader(dl_valid, sampler=sampler_valid, num_workers=self.n_jobs, drop_last=True)

        save_path = get_or_create_path(save_path)

        stop_steps = 0
        train_loss = 0
        best_score = -np.inf
        best_epoch = 0
        evals_result["train"] = []
        evals_result["valid"] = []

View on GitHub (pinned to 79633dd950)

Solutions

  1. Manually check dataset.prepare('train', ...) and dataset.prepare('valid', ...) for emptiness.
  2. Widen the valid segment or shift its start earlier so at least one full history window fits.
  3. Verify instruments and date ranges against your dumped qlib data.
  4. Reduce the handler's step/history length if it exceeds the segment length.

Example fix

# before
segments = {'train': ('2010-01-01', '2014-12-31'), 'valid': ('2015-01-01', '2015-01-10')}

# after
segments = {'train': ('2010-01-01', '2014-12-31'), 'valid': ('2015-01-01', '2015-06-30')}
Defensive patterns

Strategy: validation

Validate before calling

for seg in ('train', 'valid'):
    dl = dataset.prepare(seg, col_set=['feature', 'label'], data_key='learn')
    if dl.empty:
        raise RuntimeError(f"segment '{seg}' empty before fit; check segments and history-window length")

Try / catch

try:
    model.fit(dataset)
except ValueError as e:
    if 'Empty data from dataset' in str(e):
        # shorten handler step or widen segments, then retry
        ...
    raise

Prevention

When it happens

Trigger: fit(dataset) with an empty train or valid DataFrame: segment dates outside data coverage, no matching instruments, handler dropping all rows, or a valid segment too short for the TSDataHandler's step size to produce any sample.

Common situations: Short valid windows (e.g. one month) that get fully consumed by history-window lookback; instrument lists for a different market; date-format parsing issues in segment config; alpha360-style handlers needing long history before the first usable sample.

Related errors


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