Main Ecosystems
HomePython CorePandas ReferenceNumPy ScientificFastAPI & PydanticDjango Enterprise
More Ecosystems
Environment & SetupRequests & HTTPAsyncIO ConcurrencyObject-Oriented OOPPyTorch Deep LearningScikit-Learn MLFlask FrameworkWeb ScrapingDatabase & ORMDevOps & Docker

Scikit-Learn: TypeError: The feature_names parameter of plot_tree must be an instance of list or None

Verified FixPython 3.10+Scikit-Learn 1.4+, Pandas 2.2+Silo: scikit-learn

Quick Fix / Solution Rapide

This error occurs when Python passes a pandas Index (df.columns) or a numpy array to plot_tree(feature_names=...). Convert feature_names explicitly to a Python list using feature_names=list(df.columns) or df.columns.tolist().

Root Cause Analysis

This error occurs when Python code visualizing a Decision Tree classifier or regressor calls sklearn.tree.plot_tree(clf, feature_names=df.columns) and passes a Pandas Index object, NumPy array, or tuple instead of a native Python list.

Root Cause 1: Strict Parameter Type Validation in Modern Scikit-Learn

Scikit-Learn 1.2+ introduced strict declarative parameter validation across all public functions and estimators (via @validate_params). The parameter specification for plot_tree strictly defines feature_names: [list of str, None]. In older versions, passing a Pandas Index (df.columns) was accepted via duck typing. In modern versions, passing a pd.Index or np.ndarray raises TypeError: The 'feature_names' parameter of plot_tree must be an instance of 'list' or None, got: Index(['col1', 'col2']).

Root Cause 2: Passing df.columns Directly Without .tolist()

Developers training models on Pandas DataFrames naturally pass feature_names=df.columns or feature_names=X.columns. Because df.columns returns a pandas.core.indexes.base.Index instance rather than a Python list, type validation fails immediately.

Root Cause 3: Passing NumPy Arrays from Model.feature_names_in_

clf.feature_names_in_ is stored as a NumPy array (np.ndarray). Passing feature_names=clf.feature_names_in_ fails with the same TypeError.

Root Cause 4: Class Names Parameter Experiencing Similar Constraint

The class_names parameter in plot_tree enforces identical type constraints: it requires a list of str or bool (or None), rejecting raw arrays or series.

Reproduction Code (MCVE)

Example: Bug Reproduction
# Simulating Scikit-Learn 1.2+ strict parameter validation in plot_tree
class MockPandasColumnsIndex:
    def __init__(self, names: list):
        self.names = names

    def __repr__(self):
        return f"Index({self.names}, dtype='object')"

def mock_plot_tree(decision_tree_model, feature_names=None):
    # Scikit-Learn strict parameter validation check
    if feature_names is not None and not isinstance(feature_names, list):
        raise TypeError(
            f"The 'feature_names' parameter of plot_tree must be an instance of 'list' or None, "
            f"got: {type(feature_names).__name__} ({repr(feature_names)}). "
            "Convert to list using list(df.columns) or df.columns.tolist()."
        )
    return "Tree plotted successfully"

# Passing raw Pandas Index object triggers TypeError
raw_columns = MockPandasColumnsIndex(["age", "income", "credit_score"])
mock_plot_tree(None, feature_names=raw_columns)

Solution 1: Convert df.columns to a Python List Using .tolist()

Convert the Pandas Index to a native list using list(df.columns) or df.columns.tolist() before passing it to plot_tree.

Example: Recommended Solution
from sklearn.tree import DecisionTreeClassifier, plot_tree
import pandas as pd
import numpy as np

# Create sample dataset
df = pd.DataFrame({
    "feature_a": [1.0, 2.0, 3.0, 4.0],
    "feature_b": [10.0, 20.0, 15.0, 25.0],
    "target": [0, 0, 1, 1]
})

X = df[["feature_a", "feature_b"]]
y = df["target"]

clf = DecisionTreeClassifier(max_depth=2)
clf.fit(X, y)

# Solution 1: Explicit conversion to list
feature_names_list = list(X.columns) # or X.columns.tolist()
class_names_list = ["Class_0", "Class_1"]

print("Feature names list type:", type(feature_names_list))
assert isinstance(feature_names_list, list)

# Verification that plot_tree receives valid list
# tree_nodes = plot_tree(clf, feature_names=feature_names_list, class_names=class_names_list)
print("Decision tree configured with valid feature names:", feature_names_list)

Solution 2: Convert clf.feature_names_in_ with tolist()

If referencing the fitted estimator's feature names, convert clf.feature_names_in_.tolist().

Example: Alternative Solution
import numpy as np

# Solution 2: Convert numpy feature_names_in_ array to list
feature_array = np.array(["sepal_length", "sepal_width", "petal_length"])
safe_feature_list = feature_array.tolist()

print("Converted feature names:", safe_feature_list)
assert isinstance(safe_feature_list, list)

The same rule applies to class_names: if your classes are integers ([0, 1]), you must convert them to strings inside a list: class_names=[str(c) for c in clf.classes_]. Passing a list of integers will raise a TypeError stating that elements must be strings.

Contrast df.columns with df.columns.tolist(): df.columns is a Pandas Index; df.columns.tolist() produces a standard Python list.