python-poetry / python-poetry/tomlkit

Regression in 0.15.1: valid out-of-order child table raises KeyAlreadyPresent

Open
#571 0 comments 0 reactions 0 assignees View on GitHub

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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.