Skip to content

create_branch and create_tag replace an existing ref of the same name #4187

Closed

Description

@RyanLin5967

Apache Iceberg version

0.12.0 (latest release)

Please describe the bug 🐞

Currently, create_branch and create_tag set the ref without checking whether it exists, so an existing branch is reset and loses its commits, and a tag moves. Java refuses an existing name with Ref dev already exists.

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

cat = SqlCatalog("c", uri="sqlite:///:memory:", warehouse=f"file://{tempfile.mkdtemp()}")
cat.create_namespace("ns")
t = cat.create_table("ns.t", schema=pa.schema([("x", pa.int64())]))
t.append(pa.table({"x": [1]}))
s1 = t.current_snapshot().snapshot_id
t.manage_snapshots().create_branch(s1, "dev").create_tag(s1, "v1").commit()
t.append(pa.table({"x": [2]}), branch="dev")
t.append(pa.table({"x": [3]}))

t.manage_snapshots().create_branch(s1, "dev").commit()
print(t.scan().use_ref("dev").to_arrow()["x"].to_pylist())
# [1], should raise; the commit holding 2 is now on no ref

t.manage_snapshots().create_tag(t.current_snapshot().snapshot_id, "v1").commit()
print(sorted(t.scan().use_ref("v1").to_arrow()["x"].to_pylist()))
# [1, 3], should raise and leave v1 at [1]

remove_branch and remove_tag check nothing either: remove_branch("main") is accepted and the table then reads as empty.

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. tanmayrauth commented on Oct 30, 2026

    @tanmayrauth
    Contributor

    Can I work on this?

  2. deepdave98 commented on Nov 9, 2026

    @deepdave98
    Contributor

    I have a fix for this ready: create_branch and create_tag now raise ValueError("Ref x already exists") when the name is taken, including by an earlier operation in the same chain, and remove_branch / remove_tag raise for a missing name, for the wrong kind of ref, and for main, with the same messages as Java's UpdateSnapshotReferencesOperation. Unit tests cover each case and the script in this issue now raises on both re-creates. Opening the PR now; @tanmayrauth, if you already have a branch for this, say so and I will defer to it.

  3. added a commit that references this issue on Nov 11, 2026
    639a3bf
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