Repository: numpy/numpy
Issue category: Feature Request

ENH: Better error message for `np.put_along_axis`
### Proposed new feature or change:

In the following code snippet and its corresponding traceback,
```py
arr = np.array([[10, 30, 20], [60, 40, 50]])
indices = np.array([[1], [0]])
values = np.array([[-1], [-2]])

np.put_along_axis(arr, indices, values, axis=None)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[43], line 5
      2 indices = np.array([[1], [0]])
      3 values = np.array([[-1], [-2]])
----> 5 np.put_along_axis(arr, indices, values, axis=None)

File ~/Applications/miniconda3/envs/np/lib/python3.10/site-packages/numpy/lib/shape_base.py:260, in put_along_axis(arr, indices, values, axis)
    257     arr_shape = arr.shape
    259 # use the fancy index
--> 260 arr[_make_along_axis_idx(arr_shape, indices, axis)] = values

File ~/Applications/miniconda3/envs/np/lib/python3.10/site-packages/numpy/lib/shape_base.py:32, in _make_along_axis_idx(arr_shape, indices, axis)
     30     raise IndexError('`indices` must be an integer array')
     31 if len(arr_shape) != indices.ndim:
---> 32     raise ValueError(
     33         "`indices` and `arr` must have the same number of dimensions")
     34 shape_ones = (1,) * indices.ndim
     35 dest_dims = list(range(axis)) + [None] + list(range(axis+1, indices.ndim))

ValueError: `indices` and `arr` must have the same number of dimensions
```

the `indices` in the `ValueError` refers to the fancy index (`_make_along_axis_idx(arr_shape, indices, axis)`) but it causes confusion as it can also mean the `indices` passed by the user for the `indices` arg in `np.put_along_axis`. Nevertheless, it does not throw a clear error why the input arguments passed are invalid.

One partial solution is to rename `indices` of `_make_along_axis_idx` as `fancy_index` but that in itself does not explain what's causing the error. Or else, we can also possibly add an additional error check for the case where axis is None here:
https://github.com/numpy/numpy/blob/5ac5c15e8736ecb687dff3748aec7b3d57e81e1b/numpy/lib/_shape_base_impl.py#L254


Functions to edit:
numpy/lib/_shape_base_impl.py:take_along_axis
numpy/lib/_shape_base_impl.py:put_along_axis

Patch:
diff --git a/numpy/lib/_shape_base_impl.py b/numpy/lib/_shape_base_impl.py
index 68453095db7e..b2e98ab8866a 100644
--- a/numpy/lib/_shape_base_impl.py
+++ b/numpy/lib/_shape_base_impl.py
@@ -162,6 +162,9 @@ def take_along_axis(arr, indices, axis):
     """
     # normalize inputs
     if axis is None:
+        if indices.ndim != 1:
+            raise ValueError(
+                'when axis=None, `indices` must have a single dimension.')
         arr = arr.flat
         arr_shape = (len(arr),)  # flatiter has no .shape
         axis = 0
@@ -252,6 +255,9 @@ def put_along_axis(arr, indices, values, axis):
     """
     # normalize inputs
     if axis is None:
+        if indices.ndim != 1:
+            raise ValueError(
+                'when axis=None, `indices` must have a single dimension.')
         arr = arr.flat
         axis = 0
         arr_shape = (len(arr),)  # flatiter has no .shape

Test patch: diff --git a/numpy/lib/tests/test_shape_base.py b/numpy/lib/tests/test_shape_base.py
index 609b77720c86..2b03fdae39b5 100644
--- a/numpy/lib/tests/test_shape_base.py
+++ b/numpy/lib/tests/test_shape_base.py
@@ -63,6 +63,8 @@ def test_invalid(self):
         assert_raises(IndexError, take_along_axis, a, ai.astype(float), axis=1)
         # invalid axis
         assert_raises(AxisError, take_along_axis, a, ai, axis=10)
+        # invalid indices
+        assert_raises(ValueError, take_along_axis, a, ai, axis=None)
 
     def test_empty(self):
         """ Test everything is ok with empty results, even with inserted dims """
@@ -104,6 +106,24 @@ def test_broadcast(self):
         put_along_axis(a, ai, 20, axis=1)
         assert_equal(take_along_axis(a, ai, axis=1), 20)
 
+    def test_invalid(self):
+        """ Test invalid inputs """
+        a_base = np.array([[10, 30, 20], [60, 40, 50]])
+        indices = np.array([[0], [1]])
+        values = np.array([[2], [1]])
+
+        # sanity check
+        a = a_base.copy()
+        put_along_axis(a, indices, values, axis=0)
+        assert np.all(a == [[2, 2, 2], [1, 1, 1]])
+
+        # invalid indices
+        a = a_base.copy()
+        with assert_raises(ValueError) as exc:
+            put_along_axis(a, indices, values, axis=None)
+        assert "single dimension" in str(exc.exception)
+
+
 
 class TestApplyAlongAxis:
     def test_simple(self):