pandas-dev/pandas · error · ValueError
{k} is not a valid identifier
Error message
{k} is not a valid identifier What it means
Raised by register_option (config.py:572-574) as a ValueError when any path segment of the dotted key does not match the regex `^tokenize.Name$` (a Python identifier). Each component of the dotted key must be a legal identifier on its own.
Source
Thrown at pandas/_config/config.py:574
import tokenize
key = key.lower()
if key in _registered_options:
raise OptionError(f"Option '{key}' has already been registered")
if key in _reserved_keys:
raise OptionError(f"Option '{key}' is a reserved key")
# 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 themView on GitHub (pinned to 71959b8cb9)
Solutions
- Use only identifier-safe characters: letters, digits (not leading), underscores within each segment.
- Sanitize each segment with re.sub(r'\W', '_', seg) and ensure it does not start with a digit.
- Validate with `seg.isidentifier()` per segment before calling register_option.
Example fix
# before
cf.register_option('display.1col', 1) # 1col is not a valid identifier
# after
cf.register_option('display.first_col', 1) Defensive patterns
Strategy: validation
Validate before calling
import re, tokenize
def valid_segments(key: str) -> bool:
return all(re.match('^' + tokenize.Name + '$', seg) for seg in key.lower().split('.')) Type guard
def is_valid_option_key(key: str) -> bool:
import re, tokenize
return all(re.match('^' + tokenize.Name + '$', s) for s in key.split('.')) Prevention
- Use only Python-identifier segments (snake_case) in option keys.
- Sanitize dynamic segments with re.sub(r'\W+', '_', s) and prefix a letter if it starts with a digit.
- Add a unit test asserting key validity before registration.
When it happens
Trigger: cf.register_option('display.1col', 1) — '1col' starts with a digit; or 'display.foo-bar' where 'foo-bar' contains a hyphen.
Common situations: Embedding user input or numeric values into an option key; using kebab-case instead of dot.snake_case.
Related errors
- {k} is a python keyword
- No such keys(s): {pat!r}
- Option '{key}' has already been registered
- Option '{key}' is a reserved key
- Path prefix to option '{option}' is already an option
AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07).
Data as JSON: /api/errors/078c91da19e5114d.
Report an issue: GitHub.