Why does qcut fail with a bin edges must be unique error?
Short answer
qcut computes bin edges from quantiles, so a column with many repeated values produces duplicate edges and raises. Pass duplicates="drop" to merge them, accepting that you get fewer bins than you asked for.
The short version
qcut places the bin edges at quantiles of your data. If many values are identical, several quantiles land on the same number, producing duplicate edges, and pandas raises rather than guess. Pass duplicates="drop" to merge the duplicate edges, but understand that you then get fewer bins than you requested.
Seeing the error
import pandas as pd
s = pd.Series([1, 1, 1, 2, 3])
pd.qcut(s, 4)
# ValueError: Bin edges must be unique
Three of the five values are 1, so the 25th and 50th percentiles are both 1. Two bin edges would be identical, which would create an empty, meaningless bin. Pandas refuses.
The fix, and its cost
pd.qcut(s, 4, duplicates="drop").nunique() # 2 , not 4
duplicates="drop" merges the identical edges, and you get two bins instead of four. That is the honest outcome: the data does not support four equal-sized groups, because too many values are tied. The argument does not solve the problem, it just stops the error and tells you the truth about your data.
Why this is a data signal, not just a bug
The error is telling you something real: your column is heavily concentrated on a few values. Asking for quartiles of such a column is asking for something that does not exist, because you cannot split tied values across different bins. Before silently dropping duplicates, ask whether quantile binning is appropriate at all for this distribution.
When cut is the better choice
If the boundaries have real meaning (price bands, age groups), use cut with explicit edges instead. It does not care about ties, because you chose the edges rather than deriving them from the data.
pd.cut(s, bins=[0, 1, 2, 3])
This always works and produces bins you can explain, at the cost of unequal group sizes.
The trade-off in one line
qcut gives equal-sized groups with data-dependent boundaries. cut gives meaningful boundaries with unequal group sizes. Ties break qcut, because equal-sized groups become impossible. Choose based on which property you actually need.
Checking before you bin
Look at the concentration first, so the error does not surprise you.
s.value_counts(normalize=True).head()
If one value accounts for a large share of the rows, quantile binning will struggle. A column where half the rows are zero (common with amounts and counts) is the classic case, and there the right move is often to treat zero as its own category and bin only the non-zero values.