Skip to content

feat: send Idempotency-Key on REST mutations when the server advertises it - #4310

Merged
Fokko merged 1 commit into
apache:mainfrom
YuangGao:feat/rest-idempotency-key
Nov 10, 2026
Merged

Fokko merged 1 commit into
apache:mainfrom
YuangGao:feat/rest-idempotency-key

Conversation

@YuangGao

@YuangGao YuangGao commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

Closes #4290

Rationale for this change

  • A REST server can advertise idempotency-key-lifetime, after which clients send an Idempotency-Key (UUIDv7) on mutations and reuse it on retry, so a retried commit can't apply twice. PyIceberg sent no key and never retried POST.
  • With the lifetime advertised, each mutation now carries a fresh key, and the rest.client.* retry policy also covers POST, reusing the key across retries, as Java's RESTSessionCatalog does.
  • The lifetime itself isn't enforced: urllib3 retries are bounded and finish well within typical lifetimes.

Are these changes tested?

  • test_rest.py — mutations carry a UUIDv7 key only when advertised, a different one per operation, and reads carry none; a POST retried after a 503 reuses its key.

Are there any user-facing changes?

  • Against servers that advertise idempotency-key-lifetime, mutations send Idempotency-Key and POST is retried under rest.client.*.

@Fokko Fokko left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice feature! 🙌 The uuid7 fallback is correct per RFC 9562 (version 7, variant 0b10) and gating the retry policy on the advertised lifetime matches Java's RESTSessionCatalog. Verified the key is reused across retries. Thanks @YuangGao!

@Fokko
Fokko added this pull request to the merge queue Nov 10, 2026
Merged via the queue into apache:main with commit 1a5b751 Nov 10, 2026
20 checks passed
krishan711 added a commit to krishan711/iceberg-python that referenced this pull request Nov 12, 2026
…of-structs

* upstream/main: (78 commits)
  fix(io): keep null lists of structs when projecting Arrow data (apache#4065)
  Skip unknown nested fields when resolving Avro read schemas (apache#4289)
  fix(expressions): reject non-finite floats on conversion to Decimal (apache#4287)
  fix: handle negative-scale Decimals in increment, decrement and truncate_decimal (apache#4285)
  Match NaN partition values with `IsNaN` in partition predicates (apache#4281)
  Fix append when a data column is named like a partition helper column (apache#4344)
  Widen decimal literal precision in scan filters (apache#4348)
  Add row-lineage support with Spark tests (apache#3972)
  Serialize purgeRequested as a lowercase boolean in REST drop_table (apache#4341)
  Validate each branch against its own commits on retry (apache#4317)
  Core: Compare upsert rows column by column instead of cell by cell (apache#4334)
  Core: Write added files under the partition spec they were planned with (apache#4338)
  Core: Check whether a failed last commit attempt landed before cleanup (apache#4339)
  REST: Use the standard User-Agent format (apache#4330)
  SQL: Accept an existing SQLAlchemy engine in SqlCatalog (apache#4336)
  Expose catalog labels on Table (apache#4321)
  Respect REST endpoint capabilities when checking view existence (apache#4337)
  Reject existing ref names in create_branch and create_tag (apache#4319)
  Assert every ref a transaction writes, not just the first (apache#4315)
  feat: send Idempotency-Key on REST mutations when the server advertises it (apache#4310)
  ...

# Conflicts:
#	pyiceberg/io/pyarrow.py
#	tests/io/test_pyarrow.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

REST catalog: send Idempotency-Key on mutations and retry safely when the server advertises it

2 participants