{"record":{"id":"fbe9f674f32534f9","repo":"TheAlgorithms/Python","slug":"decision-tree-not-yet-trained","errorCode":null,"errorMessage":"Decision tree not yet trained","messagePattern":"Decision tree not yet trained","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"machine_learning/decision_tree.py","lineNumber":155,"sourceCode":"\n        return\n\n    def predict(self, x):\n        \"\"\"\n        predict:\n        @param x: a floating point value to predict the label of\n        the prediction function works by recursively calling the predict function\n        of the appropriate subtrees based on the tree's decision boundary\n        \"\"\"\n        if self.prediction is not None:\n            return self.prediction\n        elif self.left is not None and self.right is not None:\n            if x >= self.decision_boundary:\n                return self.right.predict(x)\n            else:\n                return self.left.predict(x)\n        else:\n            raise ValueError(\"Decision tree not yet trained\")\n\n\nclass TestDecisionTree:\n    \"\"\"Decision Tres test class\"\"\"\n\n    @staticmethod\n    def helper_mean_squared_error_test(labels, prediction):\n        \"\"\"\n        helper_mean_squared_error_test:\n        @param labels: a one dimensional numpy array\n        @param prediction: a floating point value\n        return value: helper_mean_squared_error_test calculates the mean squared error\n        \"\"\"\n        squared_error_sum = float(0)\n        for label in labels:\n            squared_error_sum += (label - prediction) ** 2\n\n        return float(squared_error_sum / labels.size)","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/TheAlgorithms/Python/blob/f5988cc09713315817df6a7e327e258013a94440/machine_learning/decision_tree.py#L137-L173","documentation":"Raised by DecisionTree.predict on a tree whose self.prediction is None and which has neither a left nor a right subtree. That state means train() never ran (or never reached a leaf assignment), so there is no decision boundary or leaf value to predict with.","triggerScenarios":"Creating dt = DecisionTree() and calling dt.predict(5.0) before any dt.train(x, y) call; also reachable if train exited early without setting self.prediction due to a subclass override.","commonSituations":"Forgetting to train in a script that loads a preprocessed dataset, reusing a tree object after resetting fields, or control flow that skips the training branch when a cache miss happens.","solutions":["Call train(x, y) on the root tree before any predict().","Track trained state in your own code (e.g. a fitted flag) and train lazily on first predict.","If the error persists after training, verify you are calling predict on the same root object you trained, not a fresh instance."],"exampleFix":"# before\ndt = DecisionTree()\ndt.predict(3.0)\n\n# after\ndt = DecisionTree()\ndt.train(x_train, y_train)\ndt.predict(3.0)","handlingStrategy":"validation","validationCode":"if dt.prediction is None and dt.left is None:\n    dt.train(x_train, y_train)\ndt.predict(3.0)","typeGuard":"def is_trained(tree) -> bool:\n    return tree.prediction is not None or (tree.left is not None and tree.right is not None)","tryCatchPattern":"try:\n    dt.predict(x)\nexcept ValueError as e:\n    if \"not yet trained\" in str(e):\n        dt.train(x_train, y_train)\n        return dt.predict(x)\n    raise","preventionTips":["Train immediately after construction in the same function.","Keep a fitted flag in your wrapper class.","Guard predict() entry points with an is_trained check."],"tags":["machine-learning","decision-tree","state-error","predict-before-fit"],"backgroundTag":null,"analyzedSha":"f5988cc09713315817df6a7e327e258013a94440","analyzedAt":"2026-08-14T17:30:07.041Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}