pypa/pip · error · ConfigurationFileCouldNotBeLoaded

<dynamic: configparser error>

Error message

<dynamic: configparser error>

What it means

Raised when pip's config file parser (configparser.RawConfigParser) hits a structural error while reading a pip config / requirements configuration file (e.g. duplicate options, malformed sections, or missing section headers). It is wrapped in ConfigurationFileCouldNotBeLoaded so the user gets a friendly message naming the offending file rather than a raw configparser traceback. The underlying configparser.Error (DuplicateOptionError, MissingSectionHeaderError, DuplicateSectionError, etc.) is stored in .error.

Source

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

    def _construct_parser(self, fname: str) -> RawConfigParser:
        parser = configparser.RawConfigParser()
        # If there is no such file, don't bother reading it but create the
        # parser anyway, to hold the data.
        # Doing this is useful when modifying and saving files, where we don't
        # need to construct a parser.
        if os.path.exists(fname):
            locale_encoding = get_locale_encoding()
            try:
                parser.read(fname, encoding=locale_encoding)
            except UnicodeDecodeError:
                # See https://github.com/pypa/pip/issues/4963
                raise ConfigurationFileCouldNotBeLoaded(
                    reason=f"contains invalid {locale_encoding} characters",
                    fname=fname,
                )
            except configparser.Error as error:
                # See https://github.com/pypa/pip/issues/4893
                raise ConfigurationFileCouldNotBeLoaded(error=error)
        return parser

    def _load_environment_vars(self) -> None:
        """Loads configuration from environment variables"""
        self._config[kinds.ENV_VAR].setdefault(":env:", {})
        self._config[kinds.ENV_VAR][":env:"].update(
            self._normalized_keys(":env:", self.get_environ_vars())
        )

    def _normalized_keys(
        self, section: str, items: Iterable[tuple[str, Any]]
    ) -> dict[str, Any]:
        """Normalizes items to construct a dictionary with normalized keys.

        This routine is where the names become keys and are made the same
        regardless of source - configuration files or environment.
        """
        normalized = {}

View on GitHub (pinned to d7d0d0a394)

Solutions

  1. Open the config file named in the error and fix the reported configparser issue (add the missing [section] header, remove the duplicate key, or correct syntax).
  2. Validate with 'python -m configparser -c "import configparser; c=configparser.ConfigParser(); c.read(\"<file>\")"' or pip config debug to see which file fails.
  3. If unsure which file is being loaded, run with PIP_CONFIG_FILE set to a known-good file to isolate the source.
  4. As a temporary workaround, run with --no-input and an explicit --config-file, or --isolated to skip config loading entirely.

Example fix

; before
index-url = https://pypi.org/simple
[global]
trusted-host = pypi.org

; after (section header must come first)
[global]
index-url = https://pypi.org/simple
trusted-host = pypi.org
Defensive patterns

Strategy: try-catch

Validate before calling

import configparser, sys
p = configparser.RawConfigParser()
try:
    p.read(path, encoding='utf-8')
except configparser.Error as e:
    print(f'config invalid: {e}'); sys.exit(1)
print('config OK')

Type guard

def is_valid_config_file(path: str) -> bool:
    import configparser
    p = configparser.RawConfigParser()
    try:
        p.read(path, encoding='utf-8')
        return True
    except configparser.Error:
        return False

Try / catch

from pip._internal.exceptions import ConfigurationFileCouldNotBeLoaded
try:
    configuration.load()
except ConfigurationFileCouldNotBeLoaded as e:
    # e.fname, e.reason, e.error (configparser.Error)
    log.error('Config %s failed: %s', e.fname, e.reason)

Prevention

When it happens

Trigger: Hit during configuration loading (Configuration.load() -> _construct_parser) when the file exists but contains INI syntax that configparser rejects: a line before any [section], a duplicate key/section, or an option assignment parser cannot parse. PIP_CONFIG_FILE pointing at a hand-edited file is the most common trigger.

Common situations: Editing pip.conf / pip.ini manually and introducing a typo; copy-pasting a pip config that uses 'key=value' without a leading [global]/[install] section; switching from a requirements.txt-style flat file into pip.conf without adding sections; duplicate 'index-url' / 'find-links' keys under the same section.

Related errors


AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04). Data as JSON: /data/errors/f98df96fce4ab48a.json. Report an issue: GitHub.