{"record":{"id":"1e4ea77db9684688","repo":"pandas-dev/pandas","slug":"path-prefix-to-option-option-is-already-an-opt","errorCode":null,"errorMessage":"Path prefix to option '{option}' is already an option","messagePattern":"Path prefix to option '(.+?)' is already an option","errorType":"exception","errorClass":"OptionError","httpStatus":null,"severity":"error","filePath":"pandas/_config/config.py","lineNumber":583,"sourceCode":"    # the default value should be legal\n    if validator:\n        validator(defval)\n\n    # walk the nested dict, creating dicts as needed along the path\n    path = key.split(\".\")\n\n    for k in path:\n        if not re.match(\"^\" + tokenize.Name + \"$\", k):\n            raise ValueError(f\"{k} is not a valid identifier\")\n        if keyword.iskeyword(k):\n            raise ValueError(f\"{k} is a python keyword\")\n\n    cursor = _global_config\n    msg = \"Path prefix to option '{option}' is already an option\"\n\n    for i, p in enumerate(path[:-1]):\n        if not isinstance(cursor, dict):\n            raise OptionError(msg.format(option=\".\".join(path[:i])))\n        if p not in cursor:\n            cursor[p] = {}\n        cursor = cursor[p]\n\n    if not isinstance(cursor, dict):\n        raise OptionError(msg.format(option=\".\".join(path[:-1])))\n\n    # a namespace already lives here, i.e. `key` is a path prefix to one or\n    # more already-registered options; registering it would clobber them\n    # (GH#29242)\n    if isinstance(cursor.get(path[-1]), dict):\n        raise OptionError(f\"Option '{key}' is a prefix of an already-registered option\")\n\n    cursor[path[-1]] = defval  # initialize\n\n    # save the option metadata\n    _registered_options[key] = RegisteredOption(\n        key=key, defval=defval, doc=doc, validator=validator, cb=cb","sourceCodeStart":565,"sourceCodeEnd":601,"githubUrl":"https://github.com/pandas-dev/pandas/blob/3b7651241d4da534b3559b60ef128e1c34f54116/pandas/_config/config.py#L565-L601","documentation":"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]`.","triggerScenarios":"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.","commonSituations":"Designing a key hierarchy that nests below an already-registered leaf; refactoring option keys that introduce a parent/child inversion.","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."],"exampleFix":"# before\nregister_option('a.b', 1)\nregister_option('a.b.c', 2)   # OptionError: Path prefix ... is already an option\n\n# after\nregister_option('a.b_core', 1)\nregister_option('a.b.c', 2)   # 'a.b' is now a namespace","handlingStrategy":"validation","validationCode":"from pandas._config.config import _global_config, _registered_options\ndef parent_chain_is_namespace(key: str) -> bool:\n    parts = key.split('.')\n    cursor = _global_config\n    for i, p in enumerate(parts[:-1]):\n        if not isinstance(cursor, dict):\n            return False\n        if p in cursor:\n            cursor = cursor[p]\n        else:\n            return True  # new namespace segment, fine\n    return isinstance(cursor, dict)","typeGuard":"def key_is_nestable(key: str) -> bool:\n    import pandas._config.config as c\n    parts = key.split('.')\n    cursor = c._global_config\n    for p in parts[:-1]:\n        if not isinstance(cursor, dict) or p not in cursor:\n            return isinstance(cursor, dict)\n        cursor = cursor[p]\n    return isinstance(cursor, dict)","tryCatchPattern":"from pandas._config.config import OptionError\ntry:\n    register_option(key, default)\nexcept OptionError as e:\n    if 'Path prefix' in str(e):\n        # ancestor is a leaf; restructure keys and retry\n        ...\n    raise","preventionTips":["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."],"tags":["config","register-option","path-collision","hierarchy"],"backgroundTag":null,"analyzedSha":"3b7651241d4da534b3559b60ef128e1c34f54116","analyzedAt":"2026-08-11T22:10:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}