microsoft/qlib · error · ValueError

model is not fitted yet!

Error message

model is not fitted yet!

What it means

Raised by XGBModel.predict when self.model is None, which is its initial value before fit() successfully runs xgb.train and assigns the booster. It is the standard not-fitted guard for the XGBoost wrapper, mirroring sklearn's NotFittedError semantics with a ValueError.

Source

Thrown at qlib/contrib/model/xgboost.py:73

        dtrain = xgb.DMatrix(x_train.values, label=y_train_1d, weight=w_train)
        dvalid = xgb.DMatrix(x_valid.values, label=y_valid_1d, weight=w_valid)
        self.model = xgb.train(
            self._params,
            dtrain=dtrain,
            num_boost_round=num_boost_round,
            evals=[(dtrain, "train"), (dvalid, "valid")],
            early_stopping_rounds=early_stopping_rounds,
            verbose_eval=verbose_eval,
            evals_result=evals_result,
            **kwargs,
        )
        evals_result["train"] = list(evals_result["train"].values())[0]
        evals_result["valid"] = list(evals_result["valid"].values())[0]

    def predict(self, dataset: DatasetH, segment: Union[Text, slice] = "test"):
        if self.model is None:
            raise ValueError("model is not fitted yet!")
        x_test = dataset.prepare(segment, col_set="feature", data_key=DataHandlerLP.DK_I)
        return pd.Series(self.model.predict(xgb.DMatrix(x_test)), index=x_test.index)

    def get_feature_importance(self, *args, **kwargs) -> pd.Series:
        """get feature importance

        Notes
        -------
            parameters reference:
                https://xgboost.readthedocs.io/en/latest/python/python_api.html#xgboost.Booster.get_score
        """
        return pd.Series(self.model.get_score(*args, **kwargs)).sort_values(ascending=False)

View on GitHub (pinned to 79633dd950)

Solutions

  1. Call model.fit(dataset, ...) to completion before predict().
  2. If fit() failed earlier, fix that failure first; the booster is only assigned at the end of a successful fit.
  3. To reuse a trained model in another process, persist the fitted model object (pickle the whole XGBModel or its booster) and restore it, rather than re-instantiating from config alone.

Example fix

# before
model = XGBModel()
model.predict(dataset)  # ValueError: model is not fitted yet!

# after
model = XGBModel()
model.fit(dataset, num_boost_round=200)
model.predict(dataset)
Defensive patterns

Strategy: validation

Validate before calling

if model.model is None:  # booster not yet trained
    raise RuntimeError("XGBModel.fit() must run before predict()")
preds = model.predict(dataset)

Type guard

def is_fitted_xgb(model) -> bool:
    return getattr(model, "model", None) is not None

Try / catch

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

Prevention

When it happens

Trigger: Calling predict(dataset) on an XGBModel that never had fit() called; calling predict after fit() failed before self.model was assigned (e.g. empty data error, bad params); using a model object restored from config without retraining or without loading a saved booster.

Common situations: Running a backtest workflow with a model dict that instantiates XGBModel but never trains; fit() raised earlier in a pipeline and the exception was swallowed; separating train and predict scripts while sharing only the config, not the trained booster.

Related errors


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