Repository: pandas-dev/pandas (Python)

Issue:
BUG: `UnboundLocalError` when calling `pd.option_context` with an invalid key on the `main` branch
### Pandas version checks

- [x] I have checked that this issue has not already been reported.

- [ ] I have confirmed this bug exists on the [latest version](https://pandas.pydata.org/docs/whatsnew/index.html) of pandas.

- [x] I have confirmed this bug exists on the [main branch](https://pandas.pydata.org/docs/dev/getting_started/install.html#installing-the-development-version-of-pandas) of pandas.


### Reproducible Example

```python
import pandas as pd


with pd.option_context("invalid", True):
     pass
```

### Issue Description

```python-traceback

Traceback (most recent call last):
  File ~/miniforge3/envs/dev/lib/python3.13/site-packages/pandas/_config/config.py:507 in option_context
    undo = tuple((pat, get_option(pat)) for pat, val in ops)
  File ~/miniforge3/envs/dev/lib/python3.13/site-packages/pandas/_config/config.py:507 in <genexpr>
    undo = tuple((pat, get_option(pat)) for pat, val in ops)
  File ~/miniforge3/envs/dev/lib/python3.13/site-packages/pandas/_config/config.py:185 in get_option
    key = _get_single_key(pat)
  File ~/miniforge3/envs/dev/lib/python3.13/site-packages/pandas/_config/config.py:129 in _get_single_key
    raise OptionError(f"No such keys(s): {pat!r}")
OptionError: No such keys(s): 'invalid'

During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  Cell In[3], line 1
    with pd.option_context("invalid", True):
  File ~/miniforge3/envs/dev/lib/python3.13/contextlib.py:141 in __enter__
    return next(self.gen)
  File ~/miniforge3/envs/dev/lib/python3.13/site-packages/pandas/_config/config.py:512 in option_context
    for pat, val in undo:
UnboundLocalError: cannot access local variable 'undo' where it is not associated with a value
```

### Expected Behavior

In the latest stable release (2.3.3) one would get an `OptionError` instead:

```python-traceback
Traceback (most recent call last):
  Cell In[3], line 1
    with pd.option_context("invalid", True):
  File ~/miniforge3/envs/tmp/lib/python3.14/site-packages/pandas/_config/config.py:480 in __enter__
    self.undo = [(pat, _get_option(pat)) for pat, val in self.ops]
  File ~/miniforge3/envs/tmp/lib/python3.14/site-packages/pandas/_config/config.py:146 in _get_option
    key = _get_single_key(pat, silent)
  File ~/miniforge3/envs/tmp/lib/python3.14/site-packages/pandas/_config/config.py:132 in _get_single_key
    raise OptionError(f"No such keys(s): {repr(pat)}")
OptionError: "No such keys(s): 'invalid'"
```

### Installed Versions

<details>

INSTALLED VERSIONS
------------------
commit                : 531c0e3689fb1c4a1bd080263ed1869bc6fbda01
python                : 3.13.7
python-bits           : 64
OS                    : Darwin
OS-release            : 24.6.0
Version               : Darwin Kernel Version 24.6.0: Mon Jul 14 11:30:40 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T8132
machine               : arm64
processor             : arm
byteorder             : little
LC_ALL                : None
LANG                  : en_US.UTF-8
LOCALE                : en_US.UTF-8

pandas                : 3.0.0.dev0+2551.g531c0e3689
numpy                 : 2.3.3
dateutil              : 2.9.0.post0
pip                   : 25.2
Cython                : 3.1.4
sphinx                : None
IPython               : 9.6.0
adbc-driver-postgresql: None
adbc-driver-sqlite    : None
bs4                   : 4.14.2
bottleneck            : None
fastparquet           : None
fsspec                : None
html5lib              : None
hypothesis            : None
gcsfs                 : None
jinja2                : 3.1.6
lxml.etree            : None
matplotlib            : 3.10.6
numba                 : None
numexpr               : None
odfpy                 : None
openpyxl              : None
psycopg2              : None
pymysql               : None
pyarrow               : None
pyiceberg             : None
pyreadstat            : None
pytest                : 8.4.2
python-calamine       : None
pytz                  : 2025.2
pyxlsb                : None
s3fs                  : None
scipy                 : 1.16.2
sqlalchemy            : None
tables                : None
tabulate              : None
xarray                : None
xlrd                  : None
xlsxwriter            : None
zstandard             : 0.25.0
qtpy                  : None
pyqt5                 : None

</details>



Discussion:

Patch:
diff --git a/pandas/_config/config.py b/pandas/_config/config.py
index a78a50138d195..6d9e2a69abf47 100644
--- a/pandas/_config/config.py
+++ b/pandas/_config/config.py
@@ -503,6 +503,7 @@ def option_context(*args) -> Generator[None]:
         )
 
     ops = tuple(zip(args[::2], args[1::2], strict=True))
+    undo: tuple[tuple[Any, Any], ...] = ()
     try:
         undo = tuple((pat, get_option(pat)) for pat, val in ops)
         for pat, val in ops:


Test patch:
diff --git a/pandas/tests/config/test_config.py b/pandas/tests/config/test_config.py
index b704d4a2c6472..9be1bc5554dc7 100644
--- a/pandas/tests/config/test_config.py
+++ b/pandas/tests/config/test_config.py
@@ -491,3 +491,9 @@ def test_no_silent_downcasting_deprecated():
         cf.get_option("future.no_silent_downcasting")
     with tm.assert_produces_warning(Pandas4Warning, match="is deprecated"):
         cf.set_option("future.no_silent_downcasting", True)
+
+
+def test_option_context_invalid_option():
+    with pytest.raises(OptionError, match="No such keys"):
+        with cf.option_context("invalid", True):
+            pass