Skip to content

update() on an out-of-order table raises IndexError after a sub-table fragment was popped #675

Open

Description

@Upua

Versions tested: tomlkit 0.15.2 from PyPI (the newest release on 2026-10-21) and the master branch at
eddd27e43a62fe58707c311bfad2f52e72493f53 (its head on 2026-10-21); Python 3.11.10 on Linux.

Reproduce (one command):

python3 -c '
import tomlkit
doc = tomlkit.parse("[y.y.b]\nc = 1\n[y]\nd = 1\n[y.b]\ne = 2\n[y.y]\n")
doc["y"]["y"].pop("b")
doc["y"].update({"y": [{"z": 1}], "b": {"e": -0.5}})
print(tomlkit.dumps(doc))
'

The document is valid TOML: tomllib.loads reads it as {'y': {'y': {'b': {'c': 1}}, 'd': 1, 'b': {'e': 2}}}.

Expected: the update succeeds and the document can be dumped.

Observed (the same on both versions):

  File ".../tomlkit/container.py", line 1262, in __setitem__
    old_value = self._tables[map_indices[0]][key]
                ~~~~~~~~~~~~^^^^^^^^^^^^^^^^
IndexError: list index out of range

Setting the two keys one at a time (doc["y"]["y"] = [{"z": 1}], then doc["y"]["b"] = {"e": -0.5}) after the same pop does not
raise. We have not looked for the cause.

Found while testing tomlkit's editing API against the standard library's tomllib with generated documents.

Possibly related: #196 (out-of-order sections), though that report is about _insert_after, not update().

Activity

  1. rajmodi8905 commented on Oct 22, 2026

    @rajmodi8905

    Hi! I've reproduced this on eddd27e and prepared a local fix. Replacing a key split across table fragments currently removes entire later fragments, including unrelated sibling keys. The change removes only the replaced key, and drops a fragment only when it is empty. This preserves both d and b in the example.

    I added 12 regression cases covering table, array-of-tables and scalar replacements, both update orders, and with/without the pop. All 1,215 tests pass, along with Ruff lint and formatting checks. Mypy reports the same six errors on unchanged master and the patch.

    Would you be happy for me to take this issue and submit the fix?

  2. Upua commented on Oct 22, 2026

    @Upua
    Author

    Yes, please take it, and thank you for reproducing it.

    One observation from the same document that may belong in your regression cases, since your description ("removes entire later fragments, including unrelated sibling keys") sounds like the same mechanism: with or without the pop, after

    doc["y"]["y"] = [{"z": 1}]
    doc["y"]["b"] = {"e": 0}

    tomlkit.dumps(doc) and doc.unwrap() no longer contain d = 1 from the [y] table (tested on 0.15.2 and master at eddd27e). I had not filed it separately because I could not tell whether it was the same defect; if your fix keeps d there too, that would settle it.

  3. added a commit that references this issue on Oct 22, 2026
    9cfbeba
  4. rajmodi8905 commented on Oct 27, 2026

    @rajmodi8905

    Hi maintainers, the proposed fix is in #677, where the reporter has verified the reproducer and sibling-key preservation. I'd appreciate a review when you have time. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions