microsoft/qlib · error · ValueError

model is not fitted yet!

Error message

model is not fitted yet!

What it means

Thrown by TCTSModel.predict when the model's `fitted` flag is still False. fitted becomes True only at the very end of a successful fit (after reloading best fore/weight state dicts), so this guards prediction against an untrained or incompletely trained trend-cascade model.

Source

Thrown at qlib/contrib/model/pytorch_tcts.py:353

                if stop_round >= self.early_stop:
                    print("early stop")
                    break

        print("best loss:", best_loss, "@", best_epoch)
        best_param = torch.load(save_path + "_fore_model.bin", map_location=self.device)
        self.fore_model.load_state_dict(best_param)
        best_param = torch.load(save_path + "_weight_model.bin", map_location=self.device)
        self.weight_model.load_state_dict(best_param)
        self.fitted = True

        if self.use_gpu:
            torch.cuda.empty_cache()

        return best_loss

    def predict(self, dataset):
        if not self.fitted:
            raise ValueError("model is not fitted yet!")

        x_test = dataset.prepare("test", col_set="feature")
        index = x_test.index
        self.fore_model.eval()
        x_values = x_test.values
        sample_num = x_values.shape[0]
        preds = []

        for begin in range(sample_num)[:: self.batch_size]:
            if sample_num - begin < self.batch_size:
                end = sample_num
            else:
                end = begin + self.batch_size

            x_batch = torch.from_numpy(x_values[begin:end]).float().to(self.device)

            with torch.no_grad():
                if self.use_gpu:

View on GitHub (pinned to 79633dd950)

Solutions

  1. Complete model.fit(dataset) successfully, then call model.predict(dataset).
  2. If fit fails inside its retrain loop, lower/adjust lowest_valid_performance or fix the data so at least one run meets the bar and fitted gets set.
  3. To serve a previously trained model, load both saved checkpoints (fore_model.bin / *_weight_model.bin), call load_state_dict, and set model.fitted = True.

Example fix

# before
model = TCTSModel(**kwargs)
model.predict(dataset)  # ValueError

# after
model = TCTSModel(**kwargs)
model.fit(dataset)
model.predict(dataset)
Defensive patterns

Strategy: validation

Validate before calling

if not getattr(model, "fitted", False):
    raise RuntimeError("TCTSModel not fitted — run fit(dataset) before predict(dataset)")

Type guard

def tcts_ready(model) -> bool:
    return getattr(model, "fitted", False) and getattr(model, "fore_model", None) is not None

Try / catch

try:
    preds = model.predict(dataset)
except ValueError as e:
    if "not fitted" in str(e):
        model.fit(dataset)
        preds = model.predict(dataset)
    else:
        raise

Prevention

When it happens

Trigger: Calling predict(dataset) on a TCTSModel that never ran fit(), or whose fit() aborted (empty data, unsupported optimizer, failed retrain loop vs lowest_valid_performance) before setting fitted=True.

Common situations: Retrain loop exhausts attempts ('Failed! Start retraining.') and the exception propagates, yet downstream code still predicts; running predict from a restored unsaved session; notebook cell reordering.

Related errors


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