{"record":{"id":"8a7f1aaccd1ebba4","repo":"pandas-dev/pandas","slug":"option-key-has-already-been-registered","errorCode":null,"errorMessage":"Option '{key}' has already been registered","messagePattern":"Option '(.+?)' has already been registered","errorType":"exception","errorClass":"OptionError","httpStatus":null,"severity":"error","filePath":"pandas/_config/config.py","lineNumber":561,"sourceCode":"        Function of a single argument, should raise `ValueError` if\n        called with a value which is not a legal value for the option.\n    cb\n        a function of a single argument \"key\", which is called\n        immediately after an option value is set/reset. key is\n        the full name of the option.\n\n    Raises\n    ------\n    ValueError if `validator` is specified and `defval` is not a valid value.\n\n    \"\"\"\n    import keyword\n    import tokenize\n\n    key = key.lower()\n\n    if key in _registered_options:\n        raise OptionError(f\"Option '{key}' has already been registered\")\n    if key in _reserved_keys:\n        raise OptionError(f\"Option '{key}' is a reserved key\")\n\n    # 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\"","sourceCodeStart":543,"sourceCodeEnd":579,"githubUrl":"https://github.com/pandas-dev/pandas/blob/71959b8cb9b2459c16e14b34f28b178ccfe14735/pandas/_config/config.py#L543-L579","documentation":"Raised by register_option (config.py:560-561) when the lowercased key already exists in _registered_options. Option keys are case-insensitive and globally unique.","triggerScenarios":"cf.register_option('display.max_columns', 5) when 'display.max_columns' is already registered (built-in).","commonSituations":"Re-running a notebook cell that registers a custom option; a library importing pandas-config twice; re-registering after a reload.","solutions":["Guard with `if key not in cf._registered_options:` before registering.","Use set_option on an already-registered key instead of register_option.","Choose a namespaced unique key (e.g. under your library prefix)."],"exampleFix":"# before\nimport pandas._config.config as cf\ncf.register_option('display.max_columns', 5)  # already registered\n\n# after\nimport pandas._config.config as cf\nif 'display.max_columns' not in cf._registered_options:\n    cf.register_option('display.max_columns', 5)","handlingStrategy":"validation","validationCode":"import pandas._config.config as cf\ndef safe_register(key, defval, **kw):\n    key = key.lower()\n    if key in cf._registered_options:\n        return  # idempotent\n    cf.register_option(key, defval, **kw)","typeGuard":"def is_registered(key: str) -> bool:\n    import pandas._config.config as cf\n    return key.lower() in cf._registered_options","tryCatchPattern":"from pandas.errors import OptionError\ntry:\n    cf.register_option(key, defval)\nexcept OptionError:\n    pass  # already registered; acceptable","preventionTips":["Make registration idempotent in library init code.","Namespace custom options under your library prefix to avoid collisions.","Avoid re-importing modules that call register_option at top level."],"tags":["config","register-option","duplicate"],"analyzedSha":"71959b8cb9b2459c16e14b34f28b178ccfe14735","analyzedAt":"2026-08-07T01:30:20.476Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}