{"record":{"id":"113ceb5f6ca04dfc","repo":"freqtrade/freqtrade","slug":"self-class-names-is-empty-set-self-freqai-class-n","errorCode":null,"errorMessage":"self.class_names is empty, set self.freqai.class_names = ['class a', 'class b', 'class c'] inside IStrategy.set_freqai_targets method.","messagePattern":"self\\.class_names is empty, set self\\.freqai\\.class_names = \\['class a', 'class b', 'class c'\\] inside IStrategy\\.set_freqai_targets method\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"freqtrade/freqai/base_models/BasePyTorchClassifier.py","lineNumber":153,"sourceCode":"        return [self.index_to_class_name[x.item()] for x in class_ints]\n\n    def init_class_names_to_index_mapping(self, class_names):\n        self.class_name_to_index = {s: i for i, s in enumerate(class_names)}\n        self.index_to_class_name = {i: s for i, s in enumerate(class_names)}\n        logger.info(f\"encoded class name to index: {self.class_name_to_index}\")\n\n    def convert_label_column_to_int(\n        self,\n        data_dictionary: dict[str, pd.DataFrame],\n        dk: FreqaiDataKitchen,\n        class_names: list[str],\n    ):\n        self.init_class_names_to_index_mapping(class_names)\n        self.encode_class_names(data_dictionary, dk, class_names)\n\n    def get_class_names(self) -> list[str]:\n        if not self.class_names:\n            raise ValueError(\n                \"self.class_names is empty, \"\n                \"set self.freqai.class_names = ['class a', 'class b', 'class c'] \"\n                \"inside IStrategy.set_freqai_targets method.\"\n            )\n\n        return self.class_names\n\n    def train(self, unfiltered_df: DataFrame, pair: str, dk: FreqaiDataKitchen, **kwargs) -> Any:\n        \"\"\"\n        Filter the training data and train a model to it. Train makes heavy use of the datakitchen\n        for storing, saving, loading, and analyzing the data.\n        :param unfiltered_df: Full dataframe for the current training period\n        :return:\n        :model: Trained model which can be used to inference (self.predict)\n        \"\"\"\n\n        logger.info(f\"-------------------- Starting training {pair} --------------------\")\n","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/freqtrade/freqtrade/blob/1c8edfe4d1e8d11bd4b40e8fc3237c26c3a60e15/freqtrade/freqai/base_models/BasePyTorchClassifier.py#L135-L171","documentation":"get_class_names() on the PyTorch classifier base returns self.class_names, which is populated from the strategy's configuration. If it is empty, there is no way to know the label vocabulary, so a ValueError is raised telling the user to set self.freqai.class_names inside IStrategy.set_freqai_targets. The message includes an inline example of the expected assignment.","triggerScenarios":"Running a PyTorch classification model (e.g. PyTorchClassifierModel) whose strategy never assigns self.freqai.class_names, or assigns an empty list. The call typically occurs during train() setup when the model queries the class vocabulary.","commonSituations":"New classification strategy built by copying a regression template; refactoring set_freqai_targets and dropping the assignment; setting class_names on the wrong object (e.g. self.class_names instead of self.freqai.class_names).","solutions":["Inside your strategy's set_freqai_targets, add self.freqai.class_names = ['class a', 'class b', ...] matching the exact values written to the target column.","Verify the list is non-empty and matches the target vocabulary (same strings/ints, same casing).","Retrain so the class names are persisted into model metadata for later prediction."],"exampleFix":"# before\ndef set_freqai_targets(self, dataframe, metadata, **kwargs):\n    dataframe['&-target'] = (dataframe['close'].shift(-self.freqai_info['feature_parameters']['label_period_candles']) > dataframe['close']).astype(int)\n    return dataframe\n\n# after\ndef set_freqai_targets(self, dataframe, metadata, **kwargs):\n    self.freqai.class_names = ['down', 'up']\n    dataframe['&-target'] = (dataframe['close'].shift(-1) > dataframe['close']).map({0: 'down', 1: 'up'})\n    return dataframe","handlingStrategy":"validation","validationCode":"class_names = getattr(self.freqai, 'class_names', None)\nif not class_names:\n    raise RuntimeError('Set self.freqai.class_names in set_freqai_targets before training.')","typeGuard":"def has_freqai_class_names(strategy) -> bool:\n    return bool(getattr(getattr(strategy, 'freqai', None), 'class_names', None))","tryCatchPattern":null,"preventionTips":["Set self.freqai.class_names as the first line of set_freqai_targets in every classifier strategy.","Add a smoke-test that instantiates the strategy and asserts class_names is non-empty."],"tags":["freqai","pytorch","classification","strategy","config"],"backgroundTag":null,"analyzedSha":"1c8edfe4d1e8d11bd4b40e8fc3237c26c3a60e15","analyzedAt":"2026-08-15T05:09:08.096Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}