{"record":{"id":"dfaca0589bac6853","repo":"microsoft/qlib","slug":"model-is-not-fitted-yet-dfaca0","errorCode":null,"errorMessage":"model is not fitted yet!","messagePattern":"model is not fitted yet!","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"qlib/contrib/model/gbdt.py","lineNumber":94,"sourceCode":"        evals_result_callback = lgb.record_evaluation(evals_result)\n        self.model = lgb.train(\n            self.params,\n            ds[0],  # training dataset\n            num_boost_round=self.num_boost_round if num_boost_round is None else num_boost_round,\n            valid_sets=ds,\n            valid_names=names,\n            callbacks=[early_stopping_callback, verbose_eval_callback, evals_result_callback],\n            **kwargs,\n        )\n        for k in names:\n            for key, val in evals_result[k].items():\n                name = f\"{key}.{k}\"\n                for epoch, m in enumerate(val):\n                    R.log_metrics(**{name.replace(\"@\", \"_\"): m}, step=epoch)\n\n    def predict(self, dataset: DatasetH, segment: Union[Text, slice] = \"test\"):\n        if self.model is None:\n            raise ValueError(\"model is not fitted yet!\")\n        x_test = dataset.prepare(segment, col_set=\"feature\", data_key=DataHandlerLP.DK_I)\n        return pd.Series(self.model.predict(x_test.values), index=x_test.index)\n\n    def finetune(self, dataset: DatasetH, num_boost_round=10, verbose_eval=20, reweighter=None):\n        \"\"\"\n        finetune model\n\n        Parameters\n        ----------\n        dataset : DatasetH\n            dataset for finetuning\n        num_boost_round : int\n            number of round to finetune model\n        verbose_eval : int\n            verbose level\n        \"\"\"\n        # Based on existing model and finetune by train more rounds\n        ds_l = self._prepare_data(dataset, reweighter)","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/contrib/model/gbdt.py#L76-L112","documentation":"Thrown by LGBModel.predict when self.model is None, i.e. predict runs before a successful fit. The LightGBM booster only exists after lgb.train inside fit, so a fresh or failed-to-fit LGBModel cannot predict.","triggerScenarios":"model.predict(dataset) on a newly constructed LGBModel; fit raised earlier (empty data, multi-label) and the pipeline continued to predict; calling finetune (which requires an existing model) in the wrong order.","commonSituations":"Workflow misconfiguration where the train task is skipped; error swallowing that lets the prediction task start anyway.","solutions":["Call fit(dataset) successfully before predict(dataset)","Fix any prior fit failure first (most commonly errors 152/153/154 in this file)","Order operations correctly: fit -> finetune -> predict"],"exampleFix":"# before\nmodel = LGBModel()\nmodel.predict(dataset)  # ValueError\n\n# after\nmodel.fit(dataset)\nmodel.predict(dataset)","handlingStrategy":"validation","validationCode":"assert model.model is not None, \"call fit() before predict()\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Make the predict stage conditional on successful fit in workflow scripts","When using finetune, run fit first — finetune continues from self.model"],"tags":["lightgbm","lifecycle","fit-before-predict","qlib"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}