setuptools "setup.cfg" vs "pyproject.toml" Metadata Conflict in CI
When the same field lives in both setup.cfg and the [project] table of pyproject.toml, modern setuptools refuses the ambiguity. Fields declared in [project] win, and any not marked dynamic may not be read from setup.cfg.
What this error means
A build fails with setuptools complaining a field is defined in both places, or that name/version is missing because it was left in setup.cfg while [project] exists. The build worked before [project] was added to pyproject.toml.
error: 'version' is defined both in 'pyproject.toml' and 'setup.cfg'.
# or
ValueError: 'version' must be specified in the [project] table or marked as dynamic.Common causes
The same field declared in both files
Adding a [project] table to pyproject.toml while keeping [metadata] in setup.cfg duplicates fields. setuptools treats this as a conflict rather than merging.
A field left in setup.cfg but not marked dynamic
Once [project] exists, a field only read from setup.cfg/setup.py (like a computed version) must be listed under dynamic, or setuptools reports it missing.
How to fix it
Keep static metadata in one place
Move all static fields into [project] and remove the duplicates from setup.cfg.
[project]
name = "myapp"
version = "1.2.3"
requires-python = ">=3.10"Mark computed fields as dynamic
If a field is still supplied by setup.cfg/setup.py or a plugin, declare it dynamic so setuptools knows to look elsewhere.
[project]
name = "myapp"
dynamic = ["version"]
[tool.setuptools.dynamic]
version = {attr = "myapp.__version__"}How to prevent it
- Pick one metadata home - prefer
[project]in pyproject.toml. - List anything computed at build time under
dynamic. - Run
python -m buildlocally after metadata edits to catch conflicts.