{"record":{"id":"93cfa4d6d21fd84f","repo":"pandas-dev/pandas","slug":"column-s-self-selection-already-selected","errorCode":null,"errorMessage":"Column(s) {self._selection} already selected","messagePattern":"Column\\(s\\) (.+?) already selected","errorType":"exception","errorClass":"IndexError","httpStatus":null,"severity":"error","filePath":"pandas/core/base.py","lineNumber":214,"sourceCode":"        return self._selected_obj.ndim\n\n    @final\n    @cache_readonly\n    def _obj_with_exclusions(self):\n        if isinstance(self.obj, ABCSeries):\n            return self.obj\n\n        if self._selection is not None:\n            return self.obj[self._selection_list]\n\n        if len(self.exclusions) > 0:\n            return self.obj._drop_axis(self.exclusions, axis=1)\n        else:\n            return self.obj\n\n    def __getitem__(self, key):\n        if self._selection is not None:\n            raise IndexError(f\"Column(s) {self._selection} already selected\")\n\n        if isinstance(key, (list, tuple, ABCSeries, ABCIndex, np.ndarray)):\n            if len(self.obj.columns.intersection(key)) != len(set(key)):\n                bad_keys = list(set(key).difference(self.obj.columns))\n                raise KeyError(f\"Columns not found: {str(bad_keys)[1:-1]}\")\n            return self._gotitem(list(key), ndim=2)\n\n        else:\n            if key not in self.obj:\n                raise KeyError(f\"Column not found: {key}\")\n            ndim = self.obj[key].ndim\n            return self._gotitem(key, ndim=ndim)\n\n    def _gotitem(self, key, ndim: int, subset=None):\n        \"\"\"\n        sub-classes to define\n        return a sliced object\n","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/pandas-dev/pandas/blob/71959b8cb9b2459c16e14b34f28b178ccfe14735/pandas/core/base.py#L196-L232","documentation":"Raised by SelectionMixin.__getitem__ when a selection has already been made on a groupby/resample/rolling-style object and you try to select again. After the first __getitem__, _selection is set; further indexing is rejected to prevent ambiguous chaining.","triggerScenarios":"`gb = df.groupby('g')['col1']; gb['col2']` — selecting a column after already subselection via __getitem__. Hit on objects mixing SelectionMixin like groupby column selection.","commonSituations":"Chained selections in groupby pipelines; refactoring selection logic into helper functions without resetting selection.","solutions":["Select all needed columns in a single __getitem__ pass: gb[['col1','col2']].","Re-acquire the groupby object before a new selection.","Restructure to select on the DataFrame before groupby."],"exampleFix":"// before\ng = df.groupby('g')['a']\ng['b']  # raises\n\n// after\ng = df.groupby('g')[['a','b']]","handlingStrategy":"validation","validationCode":"if getattr(obj, '_selection', None) is not None:\n    raise IndexError('selection already made; re-acquire the holder to select again')","typeGuard":"def has_existing_selection(obj) -> bool:\n    return getattr(obj, '_selection', None) is not None","tryCatchPattern":"try:\n    sub = holder[key]\nexcept IndexError as e:\n    if 'already selected' in str(e):\n        holder = rebuild_holder()  # re-acquire\n        sub = holder[[existing, key]]\n    else:\n        raise","preventionTips":["Select all columns in one __getitem__ call.","Re-acquire groupby objects for new selections.","Avoid chaining selections in helper code."],"tags":["selection","groupby","indexerror","chained"],"analyzedSha":"71959b8cb9b2459c16e14b34f28b178ccfe14735","analyzedAt":"2026-08-07T01:30:20.476Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}