You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Emptying a nested array of tables before an out-of-order super-table renders invalid TOML (0.15.2, since #567) #690
The input is valid TOML, and tomlkit parses it to {'a': {'b': {'c': [{'x': 1}]}, 'y': 1}}. After the pop, doc.unwrap() is {'a': {'b': {'c': []}, 'y': 1}}, as expected.
Observed:dumps returns 'a.b.c = []\n[a]\ny = 1\n', which declares a twice:
tomlkit.exceptions.ParseError: Redefinition of an existing table at line 3 col 0
tomllib.loads rejects it too: Cannot declare ('a',) twice (at line 2, column 3).
Expected: output that parses back to {'a': {'b': {'c': []}, 'y': 1}}, for example what tomlkit.dumps(doc.unwrap()) returns:
[a]
y = 1
[a.b]
c = []
Where it comes from:#567 renders an emptied array of tables as key = []. When the array sits under a super-table that is defined later in the document, the dotted key is emitted where the [[a.b.c]] header was, before [a]. On the parent commit of #567, the same steps produce output that parses. The same happens when [a] extends a.b with a dotted key, for example [[a.b.c]]\nx = 1\n[a]\nb.z = 1\n.
Related: #553, which #567 addressed in part, and #675, another failure after removing an element from an out-of-order table.
This came up while running generated tests on pairs of tomlkit pull requests that were open at the same time (#565 and #567). The reproduction above gives the same output on 0.15.2 and on master.
This reproduces on master (d7def7d). The key = [] fallback from #567 is written at the top of the nearest header scope, so when a later fragment declares a table on its path with a header, the hoisted dotted key declares that table a second time.
A fix that writes the fallback under the header that declares it instead ([a] / b.c = [] / y = 1 for the first example) is coming as a PR shortly. It only touches rendering in container.py, but it is about 80 lines, so happy to rework it if you would prefer a different approach.
Activity
ryanchou1994 commentedon Nov 2, 2026
This reproduces on master (d7def7d). The
key = []fallback from #567 is written at the top of the nearest header scope, so when a later fragment declares a table on its path with a header, the hoisted dotted key declares that table a second time.A fix that writes the fallback under the header that declares it instead (
[a]/b.c = []/y = 1for the first example) is coming as a PR shortly. It only touches rendering incontainer.py, but it is about 80 lines, so happy to rework it if you would prefer a different approach.