Repository navigation
[Bug]: Axes.grouped_bar() with non-string orientation (e.g., NumPy array) raises ambiguous truth-value error instead of clean ValueError #30706
Description
Activity
Integers and None should not have a problem
In [4]: check_in_list(['foo', 'bar'], wibble=None)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[4], line 1
----> 1 check_in_list(['foo', 'bar'], wibble=None)
File ~/miniforge3/envs/notebook-jul25/lib/python3.13/site-packages/matplotlib/_api/__init__.py:130, in check_in_list(values, _print_supported_values, **kwargs)
128 if _print_supported_values:
129 msg += f"; supported values are {', '.join(map(repr, values))}"
--> 130 raise ValueError(msg)
ValueError: None is not a valid value for wibble; supported values are 'foo', 'bar'
In [5]: check_in_list(['foo', 'bar'], wibble=1)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[5], line 1
----> 1 check_in_list(['foo', 'bar'], wibble=1)
File ~/miniforge3/envs/notebook-jul25/lib/python3.13/site-packages/matplotlib/_api/__init__.py:130, in check_in_list(values, _print_supported_values, **kwargs)
128 if _print_supported_values:
129 msg += f"; supported values are {', '.join(map(repr, values))}"
--> 130 raise ValueError(msg)
ValueError: 1 is not a valid value for wibble; supported values are 'foo', 'bar'I don't think a numpy array would ever work in check_in_list. So if we want to do something about this, maybe there should be a type check in check_in_list itself.
Fundamentally, one could even consider why this raises at all for numpy arrays and whether numpy should care for this. Conceptually, I would have expected that np.array([1, 2]) in ["a", "b"] would just give False. That it’s not is somewhere in the implementation details between list.__contains__ and numpy.
Edit: The issue is that a in some_list essentially does
for elem in some_list:
if elem == a:
return True
return False
and == comparisons on numpy arrays don't work this way. So no, numpy can't fix this, and python list won't special case for objects that don't support == comparison to arbitrary other objects.
TL;DR: We have to handle this in _check_in_list.
@ilakkmanoharan a question on the organizational level: Have you used AI to generate the bug report? If so, how?
The background is that the content seems overly verbose and factually wrong in some details. I would like to understand how people write bug reports nowadays so that we can optimize our contribution guidelines and issue templates.
TL;DR: We have to handle this in
_check_in_list.
OTOH, we have been using check_in_list for a long time in many places and so far no user has reported getting a confusing message because they accidentally passed a numpy array where they shouldn’t. If a failure mode is only discovered by an LLM agent that is actively looking for them, do we need to worry about it?
@timhoffm I think there may be a missing "not" in your most recent comment 👀
Right. Corrected. 😇
Bug summary
Passing a non-string value (like a NumPy array) to orientation in Axes.grouped_bar() triggers a misleading “ambiguous truth value” error from _api.check_in_list. The function should instead raise a clear ValueError stating the value is not valid.
Code for reproduction
Actual outcome
Axes.grouped_bar() fails inside _api.check_in_list() because NumPy arrays cannot be evaluated in a boolean context.
Instead of raising a clear validation error, it produces a misleading NumPy truth-value error, causing the test to fail.
Expected outcome
After applying the fix, invalid inputs (including NumPy arrays) are handled gracefully, and all tests expecting a clear ValueError now pass.
Additional information
The bug occurs whenever the orientation parameter passed to Axes.grouped_bar() is not a string, such as:
orientation = np.array([1, 2, 3]) # NumPy array
orientation = 1 # integer
orientation = None # NoneType
These types trigger an internal truth-value evaluation inside _api.check_in_list, which expects a scalar comparable value (like a string).
NumPy arrays (np.array([...]))
Non-string types (integers, floats, None, lists, etc.)
Any custom object that doesn’t implement eq safely with strings
This issue has likely existed since the introduction of Axes.grouped_bar() (Matplotlib 3.11, provisional API).
Other similar Matplotlib APIs (e.g., barh, stem, etc.) already validate string-type enums, so they are not affected.
The function directly calls:
_api.check_in_list(["vertical", "horizontal"], orientation=orientation)
When orientation is a NumPy array, the expression val not in values inside check_in_list() performs elementwise comparison, returning an array of booleans.
Python then attempts to interpret that array as a single truth value, which triggers NumPy’s error:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all().
Add an early type guard before calling _api.check_in_list():
if not isinstance(orientation, str):
raise ValueError(f"{orientation!r} is not a valid value for orientation")
_api.check_in_list(["vertical", "horizontal"], orientation=orientation)
-- This ensures non-string inputs are rejected immediately and consistently,
-- prevents the ambiguous truth-value error, and
-- aligns grouped_bar() with Matplotlib’s standard API validation behavior.
Operating system
MacOS
Matplotlib Version
3.11.0.dev1446+g319295e28.d20251030
Matplotlib Backend
macosx
Python version
Python 3.13.7
Jupyter version
No response
Installation
pip