pandas-dev/pandas · error · ValueError
invalid na_position
Error message
invalid na_position: {na_position} What it means
Raised by ArrowExtensionArray.argsort when na_position is not 'last' or 'first'. The method maps na_position to pyarrow's null_placement enum and only those two strings are valid; any typo or alternate spelling (e.g. 'end', 'at_end', 'keep') is rejected.
Solutions
- Use exactly 'first' or 'last' for na_position.
- If you need nulls at the end (default), omit na_position entirely.
- Wrap user-facing API parameters and validate against {'first','last'} before forwarding.
- Check the value at runtime: assert na_position in {'first','last'}.
Example fix
# before arr = pd.array([1, None, 2], dtype="int64[pyarrow]") arr.argsort(na_position='end') # raises ValueError # after arr.argsort(na_position='last')
Defensive patterns
Strategy: validation
Validate before calling
VALID_NA_POSITIONS = {'first', 'last'}
def safe_argsort(arr, na_position='last', **kw):
if na_position not in VALID_NA_POSITIONS:
raise ValueError(f"na_position must be one of {VALID_NA_POSITIONS}, got {na_position!r}")
return arr.argsort(na_position=na_position, **kw) Type guard
def is_valid_na_position(s: str) -> bool:
return s in {'first', 'last'} Prevention
- Restrict na_position to exactly 'first' or 'last'.
- Validate at API boundaries when forwarding user input.
- Default na_position to 'last' (the pandas default) instead of guessing.
When it happens
Trigger: arr.argsort(na_position='end'); sort_values(na_position='at_end') on a pyarrow-backed Series; passing na_position='Keep' or 'NONE'.
Common situations: Users more familiar with numpy/pandas spelling variations; copying na_position values from a different API (e.g. pyarrow's null_placement names); case sensitivity ('Last' vs 'last').
Related errors
- Cannot modify read-only array
- can only insert Interval objects and NA into an…
- cannot assign without a target object
- Cannot pass both a timezone-aware dtype and tz=None
- Cannot slice with
AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11).
Data as JSON: /api/errors/5c39aee9369356b5.
Report an issue: GitHub.
Appendix: source
Thrown at pandas/core/arrays/arrow/array.py:1546
>>> pd.array([True, False, pd.NA], dtype="boolean[pyarrow]").all(skipna=False)
False
>>> pd.array([1, 0, pd.NA], dtype="boolean[pyarrow]").all(skipna=False)
False
"""
return self._reduce("all", skipna=skipna, **kwargs)
def argsort(
self,
*,
ascending: bool = True,
kind: SortKind = "quicksort",
na_position: str = "last",
**kwargs,
) -> np.ndarray:
order = "ascending" if ascending else "descending"
null_placement = {"last": "at_end", "first": "at_start"}.get(na_position, None)
if null_placement is None:
raise ValueError(f"invalid na_position: {na_position}")
result = pc.array_sort_indices(
self._pa_array, order=order, null_placement=null_placement
)
np_result = result.to_numpy()
return np_result.astype(np.intp, copy=False)
def sort(
self,
*,
ascending: bool = True,
kind: SortKind = "quicksort",
na_position: str = "last",
) -> None:
# This override replaces self._pa_array directly, bypassing __setitem__,
# so enforce the read-only guard here to stay consistent with it and
# with the base ExtensionArray.sort.
if self._readonly:View on GitHub (pinned to 3b7651241d)