pypa/pip · error · ConfigurationError

Key does not contain dot separated section and key. Perhaps…

Error message

Key does not contain dot separated section and key. Perhaps you wanted to use 'global.{name}' instead?

What it means

Raised by _disassemble_key() when a configuration key passed to pip config does not contain a dot separator. pip's configuration API requires keys in 'section.name' form (e.g. 'global.index-url'), because it maps to an INI section plus option. A bare key like 'index-url' is ambiguous and pip suggests prefixing it with a section such as 'global.'.

Solutions

  1. Prefix the key with the appropriate section: `global.`, `user.`, or `site.` — e.g. `pip config set global.index-url https://...`.
  2. Consult `pip config list` to see the correct section.key format for existing entries.
  3. If editing a specific file, use `pip config set --site global.index-url ...` (the section prefix is always required regardless of --user/--global/--site scope).

Example fix

# before
pip config set index-url https://pypi.org/simple
# after
pip config set global.index-url https://pypi.org/simple
Defensive patterns

Strategy: validation

Validate before calling

import re

def validate_config_key(key: str) -> str:
    if not re.match(r'^(global|user|site|install)\.[A-Za-z0-9_-]+$', key):
        raise ValueError(f"Config key must be 'section.name', got: {key!r}")
    return key

Type guard

def is_dotted_config_key(key: str) -> bool:
    return '.' in key and key.split('.', 1)[0] in {'global', 'user', 'site', 'install'}

Prevention

When it happens

Trigger: Running `pip config set index-url https://...` (missing section prefix), or `pip config get timeout`, or `pip config unset index-url`. Any config subcommand that ultimately calls set_value/get_value/unset_value and hits _disassemble_key with a dotless string.

Common situations: Forgetting the section prefix when scripting `pip config set`; copying a pip.conf option name without its section; muscle memory from tools that take bare option names.

Related errors


AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08). Data as JSON: /api/errors/b02163d1282b3301. Report an issue: GitHub.

Appendix: source

Thrown at src/pip/_internal/configuration.py:65

logger = getLogger(__name__)


# NOTE: Maybe use the optionx attribute to normalize keynames.
def _normalize_name(name: str) -> str:
    """Make a name consistent regardless of source (environment or file)"""
    name = name.lower().replace("_", "-")
    name = name.removeprefix("--")  # only prefer long opts
    return name


def _disassemble_key(name: str) -> list[str]:
    if "." not in name:
        error_message = (
            "Key does not contain dot separated section and key. "
            f"Perhaps you wanted to use 'global.{name}' instead?"
        )
        raise ConfigurationError(error_message)
    return name.split(".", 1)


def get_configuration_files() -> dict[Kind, list[str]]:
    global_config_files = [
        os.path.join(path, CONFIG_BASENAME) for path in appdirs.site_config_dirs("pip")
    ]

    site_config_file = os.path.join(sys.prefix, CONFIG_BASENAME)
    legacy_config_file = os.path.join(
        os.path.expanduser("~"),
        "pip" if WINDOWS else ".pip",
        CONFIG_BASENAME,
    )
    new_config_file = os.path.join(appdirs.user_config_dir("pip"), CONFIG_BASENAME)
    return {
        kinds.GLOBAL: global_config_files,
        kinds.SITE: [site_config_file],

View on GitHub (pinned to f399c37189)