Skip to content

A stale add_column reuses a dropped column's field id and schema id #4190

Open

Description

@RyanLin5967

Apache Iceberg version

0.12.0 (latest release)

Please describe the bug 🐞

Currently, UpdateSchema commits with only AssertCurrentSchemaId, so after another writer adds and drops a column, a stale handle's add_column passes the check and reuses the dropped column's field id and schema id. A handle loaded after the drop gives y field id 3.

import tempfile
import pyarrow as pa
from pyiceberg.catalog.sql import SqlCatalog
from pyiceberg.types import StringType

cat = SqlCatalog("c", uri="sqlite:///:memory:", warehouse=f"file://{tempfile.mkdtemp()}")
cat.create_namespace("ns")
cat.create_table("ns.t", schema=pa.schema([("k", pa.int64())]))

a = cat.load_table("ns.t")
b = cat.load_table("ns.t")
with b.update_schema() as u:
    u.add_column("x", StringType())
b.append(pa.table({"k": [1], "x": ["a"]}))
with b.update_schema() as u:
    u.delete_column("x")

with a.update_schema() as u:
    u.add_column("y", StringType())
# commits, should raise CommitFailedException as the last assigned field id changed

t = cat.load_table("ns.t")
print(t.scan().to_arrow().to_pylist())
# [{'k': 1, 'x': 'a'}]: the dropped column is back with its data, and y is gone
print([(s.schema_id, [(f.field_id, f.name) for f in s.fields]) for s in t.metadata.schemas])
# [(0, [(1, 'k')]), (1, [(1, 'k'), (2, 'x')]), (1, [(1, 'k'), (2, 'y')])]
# y took field id 2 and schema id 1, both already x's

Iceberg Java 1.12.0 then cannot load the table: IllegalArgumentException: Multiple entries with same key: 1=table {. Java's UpdateRequirements adds AssertLastAssignedFieldId whenever a commit adds a schema; pyiceberg defines it but never sends it.

tested on pyiceberg 0.12.0 and main

Willingness to contribute

  • I can contribute a fix for this bug independently
  • I would be willing to contribute a fix for this bug with guidance from the Iceberg community
  • I cannot contribute a fix for this bug at this time

Activity

  1. dragonknightk commented on Oct 30, 2026

    @dragonknightk
    Contributor

    Thanks a lot for the detailed report and the clear repro (´。• ᵕ •。) I'd like to take this one, and I've opened #4205, which sends AssertLastAssignedFieldIdwhenupdate_schemaadds a schema, the same way Java'sUpdateRequirements` does. I'd be really grateful if you could take a look whenever you have a moment. No rush at all, and any feedback is very welcome! (๑•̀ㅂ•́)و✧

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions