{"record":{"id":"5c39aee9369356b5","repo":"pandas-dev/pandas","slug":"invalid-na-position-na-position","errorCode":null,"errorMessage":"invalid na_position: {na_position}","messagePattern":"invalid na_position: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pandas/core/arrays/arrow/array.py","lineNumber":1546,"sourceCode":"        >>> pd.array([True, False, pd.NA], dtype=\"boolean[pyarrow]\").all(skipna=False)\n        False\n        >>> pd.array([1, 0, pd.NA], dtype=\"boolean[pyarrow]\").all(skipna=False)\n        False\n        \"\"\"\n        return self._reduce(\"all\", skipna=skipna, **kwargs)\n\n    def argsort(\n        self,\n        *,\n        ascending: bool = True,\n        kind: SortKind = \"quicksort\",\n        na_position: str = \"last\",\n        **kwargs,\n    ) -> np.ndarray:\n        order = \"ascending\" if ascending else \"descending\"\n        null_placement = {\"last\": \"at_end\", \"first\": \"at_start\"}.get(na_position, None)\n        if null_placement is None:\n            raise ValueError(f\"invalid na_position: {na_position}\")\n\n        result = pc.array_sort_indices(\n            self._pa_array, order=order, null_placement=null_placement\n        )\n        np_result = result.to_numpy()\n        return np_result.astype(np.intp, copy=False)\n\n    def sort(\n        self,\n        *,\n        ascending: bool = True,\n        kind: SortKind = \"quicksort\",\n        na_position: str = \"last\",\n    ) -> None:\n        # This override replaces self._pa_array directly, bypassing __setitem__,\n        # so enforce the read-only guard here to stay consistent with it and\n        # with the base ExtensionArray.sort.\n        if self._readonly:","sourceCodeStart":1528,"sourceCodeEnd":1564,"githubUrl":"https://github.com/pandas-dev/pandas/blob/3b7651241d4da534b3559b60ef128e1c34f54116/pandas/core/arrays/arrow/array.py#L1528-L1564","documentation":"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.","triggerScenarios":"arr.argsort(na_position='end'); sort_values(na_position='at_end') on a pyarrow-backed Series; passing na_position='Keep' or 'NONE'.","commonSituations":"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').","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'}."],"exampleFix":"# before\narr = pd.array([1, None, 2], dtype=\"int64[pyarrow]\")\narr.argsort(na_position='end')  # raises ValueError\n\n# after\narr.argsort(na_position='last')","handlingStrategy":"validation","validationCode":"VALID_NA_POSITIONS = {'first', 'last'}\n\ndef safe_argsort(arr, na_position='last', **kw):\n    if na_position not in VALID_NA_POSITIONS:\n        raise ValueError(f\"na_position must be one of {VALID_NA_POSITIONS}, got {na_position!r}\")\n    return arr.argsort(na_position=na_position, **kw)","typeGuard":"def is_valid_na_position(s: str) -> bool:\n    return s in {'first', 'last'}","tryCatchPattern":null,"preventionTips":["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."],"tags":["sorting","validation","na-position","argsort"],"backgroundTag":null,"analyzedSha":"3b7651241d4da534b3559b60ef128e1c34f54116","analyzedAt":"2026-08-11T22:10:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}