{"record":{"id":"45fcd0e8b0165258","repo":"pandas-dev/pandas","slug":"storage-must-be-python-or-pyarrow-got-storag","errorCode":null,"errorMessage":"Storage must be 'python' or 'pyarrow'. Got {storage} instead.","messagePattern":"Storage must be 'python' or 'pyarrow'\\. Got (.+?) instead\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pandas/core/arrays/string_.py","lineNumber":212,"sourceCode":"    _metadata = (\"storage\", \"_na_value\")  # type: ignore[assignment]\n\n    def __init__(\n        self,\n        storage: str | None = None,\n        na_value: libmissing.NAType | float = libmissing.NA,\n    ) -> None:\n        # infer defaults\n        if storage is None:\n            storage = config[\"mode\"][\"string_storage\"]\n            if storage == \"auto\":\n                if HAS_PYARROW:\n                    storage = \"pyarrow\"\n                else:\n                    storage = \"python\"\n\n        # validate options\n        if storage not in {\"python\", \"pyarrow\"}:\n            raise ValueError(\n                f\"Storage must be 'python' or 'pyarrow'. Got {storage} instead.\"\n            )\n        if storage == \"pyarrow\" and not HAS_PYARROW:\n            raise ImportError(\n                f\"pyarrow>={PYARROW_MIN_VERSION} is required for PyArrow \"\n                \"backed StringArray.\"\n            )\n\n        if isinstance(na_value, float) and np.isnan(na_value):\n            # when passed a NaN value, always set to np.nan to ensure we use\n            # a consistent NaN value (and we can use `dtype.na_value is np.nan`)\n            na_value = np.nan\n        elif na_value is not libmissing.NA:\n            raise ValueError(f\"'na_value' must be np.nan or pd.NA, got {na_value}\")\n\n        self._storage = cast(\"str\", storage)\n        self._na_value = na_value\n","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/pandas-dev/pandas/blob/71959b8cb9b2459c16e14b34f28b178ccfe14735/pandas/core/arrays/string_.py#L194-L230","documentation":"StringDtype.__init__ validates that the storage argument is exactly one of 'python' or 'pyarrow'. Any other value (including None after config resolution, or typos) raises ValueError. When storage is None it is first resolved from pd.options.mode.string_storage, so a misconfigured global option can also surface here.","triggerScenarios":"Calling StringDtype(storage='numpy'), StringDtype(storage='foo'), pd.array(data, dtype='string[foo]'), or setting pd.options.mode.string_storage to an invalid value and then constructing a StringDtype with storage=None.","commonSituations":"Typos in dtype strings like 'string[numpy]' or 'string[arrow]'; programmatically building storage names; a stale or wrong value in mode.string_storage config.","solutions":["Use exactly 'python' or 'pyarrow' as the storage value.","If using config, verify pd.options.mode.string_storage is 'python' or 'pyarrow' before relying on storage=None.","Validate dynamic storage strings against {'python','pyarrow'} before passing to StringDtype."],"exampleFix":"// before\ndtype = pd.StringDtype(storage='numpy')\n\n// after\ndtype = pd.StringDtype(storage='python')","handlingStrategy":"validation","validationCode":"VALID_STORAGES = {'python', 'pyarrow'}\nstorage = 'python' if storage not in VALID_STORAGES else storage\ndtype = pd.StringDtype(storage=storage)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Restrict storage to the literals 'python' or 'pyarrow'.","Validate pd.options.mode.string_storage if you pass storage=None.","Centralize dtype construction in a helper that checks the storage value."],"tags":["string-dtype","validation","config","storage"],"analyzedSha":"71959b8cb9b2459c16e14b34f28b178ccfe14735","analyzedAt":"2026-08-07T01:30:20.476Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}