microsoft/qlib · error · ValueError
CatBoost doesn't support multi-label training
Error message
CatBoost doesn't support multi-label training
What it means
Thrown by CatBoostModel.fit when the label block is not a single-column 2D array. CatBoost's Pool accepts only a 1D label (scalar per sample), so qlib squeezes the label only when it is exactly (N, 1); anything else (multi-column labels, or a raw 1D series that already lost its column axis) is rejected.
Source
Thrown at qlib/contrib/model/catboost_model.py:52
evals_result=dict(),
reweighter=None,
**kwargs,
):
df_train, df_valid = dataset.prepare(
["train", "valid"],
col_set=["feature", "label"],
data_key=DataHandlerLP.DK_L,
)
if df_train.empty or df_valid.empty:
raise ValueError("Empty data from dataset, please check your dataset config.")
x_train, y_train = df_train["feature"], df_train["label"]
x_valid, y_valid = df_valid["feature"], df_valid["label"]
# CatBoost needs 1D array as its label
if y_train.values.ndim == 2 and y_train.values.shape[1] == 1:
y_train_1d, y_valid_1d = np.squeeze(y_train.values), np.squeeze(y_valid.values)
else:
raise ValueError("CatBoost doesn't support multi-label training")
if reweighter is None:
w_train = None
w_valid = None
elif isinstance(reweighter, Reweighter):
w_train = reweighter.reweight(df_train).values
w_valid = reweighter.reweight(df_valid).values
else:
raise ValueError("Unsupported reweighter type.")
train_pool = Pool(data=x_train, label=y_train_1d, weight=w_train)
valid_pool = Pool(data=x_valid, label=y_valid_1d, weight=w_valid)
# Initialize the catboost model
self._params["iterations"] = num_boost_round
self._params["early_stopping_rounds"] = early_stopping_rounds
self._params["verbose_eval"] = verbose_eval
self._params["task_type"] = "GPU" if get_gpu_device_count() > 0 else "CPU"View on GitHub (pinned to 79633dd950)
Solutions
- Reduce the label to exactly one expression in the handler config, e.g. label: ["Ref($close, -2)/Ref($close, -1) - 1"]
- If multi-output prediction is required, use a model that supports it (e.g. a PyTorch model with a matching output head)
Example fix
# before (qlib config yaml) label: ["Ref($close, -2)/Ref($close, -1) - 1", "$volume"] # after label: ["Ref($close, -2)/Ref($close, -1) - 1"]
Defensive patterns
Strategy: validation
Validate before calling
y = dataset.prepare("train", col_set="label", data_key="learn")
assert y.values.ndim == 2 and y.values.shape[1] == 1, f"CatBoost needs a single label column, got {y.shape[1]}" Prevention
- Keep the handler label list to exactly one expression for all GBM-family models
- Add a startup assertion on label column count when sharing configs across models
When it happens
Trigger: Configuring the DatasetH label as multiple expressions (e.g. "Ref($close, -2)/Ref($close, -1) - 1; $volume/$amount"), producing y_train.values.shape[1] > 1; or a label pipeline that returns a DataFrame with != 1 columns.
Common situations: Copying a workflow config with a multi-task label; adding extra label columns for custom metrics and forgetting the model constraint; switching from a model that tolerates multi-label (e.g. some neural models) to CatBoostModel.
Related errors
- LightGBM doesn't support multi-label training
- Empty data from dataset, please check your dataset config.
- Unsupported reweighter type.
- model is not fitted yet!
- LightGBM doesn't support multi-label training
AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15).
Data as JSON: /api/errors/7d9e039bd4118c5f.
Report an issue: GitHub.