pandas-dev/pandas · error · OptionError
Path prefix to option
Error message
Path prefix to option '{option}' is already an option What it means
Raised by `register_option` inside the path-walk loop: for an intermediate segment `p` of the new key, the current `cursor` in `_global_config` is not a dict (it is already a scalar leaf value). That means an ancestor of the new key is itself a registered option, so the new nested key cannot be created. The message names the colliding ancestor via `path[:i]`.
Solutions
- Do not nest new keys under an existing leaf option; restructure so ancestors are namespaces, not values.
- If you control both keys, unregister/deprecate the leaf and re-register the hierarchy consistently.
- Choose a distinct top-level namespace for new options.
Example fix
# before
register_option('a.b', 1)
register_option('a.b.c', 2) # OptionError: Path prefix ... is already an option
# after
register_option('a.b_core', 1)
register_option('a.b.c', 2) # 'a.b' is now a namespace Defensive patterns
Strategy: validation
Validate before calling
from pandas._config.config import _global_config, _registered_options
def parent_chain_is_namespace(key: str) -> bool:
parts = key.split('.')
cursor = _global_config
for i, p in enumerate(parts[:-1]):
if not isinstance(cursor, dict):
return False
if p in cursor:
cursor = cursor[p]
else:
return True # new namespace segment, fine
return isinstance(cursor, dict) Type guard
def key_is_nestable(key: str) -> bool:
import pandas._config.config as c
parts = key.split('.')
cursor = c._global_config
for p in parts[:-1]:
if not isinstance(cursor, dict) or p not in cursor:
return isinstance(cursor, dict)
cursor = cursor[p]
return isinstance(cursor, dict) Try / catch
from pandas._config.config import OptionError
try:
register_option(key, default)
except OptionError as e:
if 'Path prefix' in str(e):
# ancestor is a leaf; restructure keys and retry
...
raise Prevention
- Design option trees top-down: register namespaces (parents) before leaves, and never register a leaf where you later need children.
- Namespace your own keys to avoid colliding with built-in leaf options.
- Audit existing registrations before adding nested keys.
When it happens
Trigger: First `register_option('a.b', 1)` (so `a.b` is a leaf), then `register_option('a.b.c', 2)` — walking to `a.b` finds a scalar, not a dict.
Common situations: Designing a key hierarchy that nests below an already-registered leaf; refactoring option keys that introduce a parent/child inversion.
Related errors
- Option ' ' is a prefix of an already-registered option
- is a python keyword
- is not a valid identifier
- Option ' ' has already been registered
- Option ' ' is a reserved key
AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11).
Data as JSON: /api/errors/1e4ea77db9684688.
Report an issue: GitHub.
Appendix: source
Thrown at pandas/_config/config.py:583
# the default value should be legal
if validator:
validator(defval)
# walk the nested dict, creating dicts as needed along the path
path = key.split(".")
for k in path:
if not re.match("^" + tokenize.Name + "$", k):
raise ValueError(f"{k} is not a valid identifier")
if keyword.iskeyword(k):
raise ValueError(f"{k} is a python keyword")
cursor = _global_config
msg = "Path prefix to option '{option}' is already an option"
for i, p in enumerate(path[:-1]):
if not isinstance(cursor, dict):
raise OptionError(msg.format(option=".".join(path[:i])))
if p not in cursor:
cursor[p] = {}
cursor = cursor[p]
if not isinstance(cursor, dict):
raise OptionError(msg.format(option=".".join(path[:-1])))
# a namespace already lives here, i.e. `key` is a path prefix to one or
# more already-registered options; registering it would clobber them
# (GH#29242)
if isinstance(cursor.get(path[-1]), dict):
raise OptionError(f"Option '{key}' is a prefix of an already-registered option")
cursor[path[-1]] = defval # initialize
# save the option metadata
_registered_options[key] = RegisteredOption(
key=key, defval=defval, doc=doc, validator=validator, cb=cbView on GitHub (pinned to 3b7651241d)