psycopg/psycopg2 · critical · Warning
pg_config --{attr_name} failed: {err}
Error message
pg_config --{attr_name} failed: {err} What it means
Raised in PostgresConfig.query() (setup.py:117) as a Warning when pg_config ran but returned a non-zero exit code with stderr output. This means the executable exists but the invocation failed - typically a broken/partial PostgreSQL install, a pg_config from a different major version, an architecture mismatch (e.g. 32-bit pg_config driving a 64-bit build), or a wrapper/shim script that errors. finalize_options() catches the Warning, prints 'Error: ...', and exits 1.
Source
Thrown at setup.py:117
<https://www.psycopg.org/docs/install.html>).
""")
sys.exit(1)
def query(self, attr_name, *, empty_ok=False):
"""Spawn the pg_config executable, querying for the given config
name, and return the printed value, sanitized. """
try:
pg_config_process = subprocess.run(
[self.pg_config_exe, "--" + attr_name],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
except OSError:
raise Warning(
f"Unable to find 'pg_config' file in '{self.pg_config_exe}'")
if pg_config_process.returncode:
err = pg_config_process.stderr.decode(errors='backslashreplace')
raise Warning(f"pg_config --{attr_name} failed: {err}")
result = pg_config_process.stdout.decode().strip()
if not result and not empty_ok:
raise Warning(f"pg_config --{attr_name} is empty")
return result
def find_on_path(self, exename, path_directories=None):
if not path_directories:
path_directories = os.environ['PATH'].split(os.pathsep)
for dir_name in path_directories:
fullpath = os.path.join(dir_name, exename)
if os.path.isfile(fullpath):
return fullpath
return None
def autodetect_pg_config_path(self):
"""Find and return the path to the pg_config executable."""
if PLATFORM_IS_WINDOWS:
return self.autodetect_pg_config_path_windows()View on GitHub (pinned to 3a6d9d6ddc)
Solutions
- Reinstall or repair the PostgreSQL client dev package so pg_config works cleanly.
- Reproduce manually: run '/path/to/pg_config --libdir' (and --includedir) and read the stderr to find the real cause.
- Reinstall to a clean PostgreSQL and use psycopg2-binary if you cannot repair the local install.
Defensive patterns
Strategy: validation
Validate before calling
import subprocess, shutil
def pg_config_attr_works(attr: str = 'libdir', path: str | None = None) -> bool:
p = path or shutil.which('pg_config')
if not p:
return False
res = subprocess.run([p, '--' + attr], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
return res.returncode == 0
assert pg_config_attr_works('libdir') and pg_config_attr_works('includedir') Try / catch
# Diagnose in CI before building: # pg_config --libdir && pg_config --includedir && pg_config --includedir-server # any non-zero exit means the install is broken - reinstall the Postgres dev package.
Prevention
- Keep exactly one PostgreSQL dev installation first on PATH to avoid version drift.
- After installing/upgrading Postgres, re-run pg_config --version and --libdir to confirm it works.
- In containers, prefer official postgres:libpq images or psycopg2-binary to dodge broken pg_config.
When it happens
Trigger: Any pg_config_helper.query('libdir'|'includedir'|'includedir-server'|'libdir' for static) during finalize_options() when that pg_config subcommand exits non-zero. The {err} field carries the decoded stderr so you can see the underlying failure.
Common situations: Multiple PostgreSQL installations with a stale pg_config first on PATH; corrupted/incomplete client packages; hand-written pg_config shims in custom images; cross-architecture or cross-version toolchain mismatches.
Related errors
- Unable to find 'pg_config' file in '{self.pg_config_exe}'
- pg_config --{attr_name} is empty
- no format specification supported by SQL
- no format conversion supported by SQL
- cannot switch from automatic field numbering to manual
AI-assisted analysis of psycopg/psycopg2@3a6d9d6ddc (2026-08-04).
Data as JSON: /data/errors/17e2e58cffbebc2d.json.
Report an issue: GitHub.