python-poetry / python-poetry/tomlkit
Regression in 0.15.1: valid out-of-order child table raises KeyAlreadyPresent
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 850
- Forks
- 162
- Avg merge
- 13m
- Merged PRs (30d)
- 2
Description
Summary
Tomlkit 0.15.1 rejects a valid document when a table contains an out-of-order
child, its concrete parent is declared afterward, and another table separates a
later sibling child.
This is a regression: tomllib and Tomlkit 0.13.3, 0.14.0, and 0.15.0 all
accept the document.
Minimal reproduction
import tomlkit
source = """\
[tool.ruff]
[tool.ruff.lint.a]
[tool.ruff.lint]
[[tool.poetry.source]]
[tool.ruff.lint.b]
"""
tomlkit.loads(source)
Actual result
tomlkit.exceptions.ParseError: Key "lint" already exists. at line 5 col 0
Expected result
The document parses successfully, matching tomllib:
{
"tool": {
"ruff": {"lint": {"a": {}, "b": {}}},
"poetry": {"source": [{}]},
}
}
Each header in the minimized example is necessary to trigger the failure. The
array-of-tables is not special: replacing [[tool.poetry.source]] with any
intervening table header also reproduces it, while removing the intervening
header makes it pass.
Regression boundary
Reproduced on Python 3.13.8 and 3.14.2:
- stdlib
tomllib: passes - Tomlkit 0.13.3: passes
- Tomlkit 0.14.0: passes
- Tomlkit 0.15.0: passes
- Tomlkit 0.15.1 and current
master: fail
Suspected root cause
The regression appears to come from the concrete+super validation added in
#530 / commit d3c76f0.
When [tool.ruff.lint.b] is appended, the existing lint entry is represented
by OutOfOrderTableProxy, while the candidate is a Table.
_validate_table_candidate() checks:
isinstance(existing, (Table, AoT)) != isinstance(v, (Table, AoT))
The proxy is table-like but fails the left-hand isinstance check, so valid
input is reported as a type conflict and raises KeyAlreadyPresent("lint").
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the minimal reproduction and inspect _validate_table_candidate() together with the OutOfOrderTableProxy and Table validation described in the report. The fix is done when the document parses successfully without KeyAlreadyPresent, while the listed older-version behavior and expected nested result remain valid.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100