Skip to content

fix: merge write-time storage options into staged commits#714

Open
ivscheianu wants to merge 2 commits into
lance-format:mainfrom
ivscheianu:fix/staged-commit-namespace-storage-options-clean
Open

fix: merge write-time storage options into staged commits#714
ivscheianu wants to merge 2 commits into
lance-format:mainfrom
ivscheianu:fix/staged-commit-namespace-storage-options-clean

Conversation

@ivscheianu

@ivscheianu ivscheianu commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

What changes are included in this PR?

Fixes #712.

StagedCommit captures storage options once at stage-create time from the catalog's static config. For path-based staged creates/replaces (no namespace), that is the only storage-options source available at that point, so write-time .option(...) values and namespace-vended credentials obtained afterward were silently dropped from the final manifest commit, falling back to ambient credential discovery instead.

This PR:

  • Adds StagedCommit.mergeStorageOptions(Map<String, String>) to layer in additional options after construction.
  • Calls it from LanceBatchWrite.commit()'s staged branch with LanceRuntime.mergeStorageOptions(writeOptions.getStorageOptions(), initialStorageOptions) — the same merge and precedence the non-staged branch and LanceSparkWriteOptions.toWriteParams() (executor-side fragment writes) already use.
  • Makes StagedCommit's constructor defensively copy the incoming storage options map, since callers (e.g. LanceSparkCatalogConfig.getStorageOptions()) can hand it an unmodifiable map, which would otherwise make the new merge throw UnsupportedOperationException on every real path-based staged create.

All six staged entry points (stageCreate[AtPath], stageReplace[AtPath], stageCreateOrReplace[AtPath]) funnel through this single LanceBatchWrite.commit() staged branch, so the fix closes the gap uniformly without touching call sites individually. AddColumnsBackfillBatchWrite/UpdateColumnsBackfillBatchWrite/SparkPositionDeltaWrite are unaffected — they never use StagedCommit and already perform their own correct merge.

Are these changes tested?

  • New tests in StagedCommitTest: mergeStorageOptions adds new keys, overrides existing keys on conflict, is a no-op for null/empty input, does not mutate the caller's map, and accepts an unmodifiable base map (regression test for the UnsupportedOperationException risk above).
  • New tests in LanceBatchWriteTest: LanceBatchWrite.commit() merges initialStorageOptions into a StagedCommit that started with empty options (simulating stageCreateAtPath), including a full round-trip through an actual dataset commit; and a separate test confirming write-time-only options survive the merge while initialStorageOptions still wins on key conflict, matching LanceRuntime.mergeStorageOptions's documented precedence.
  • ./mvnw test -pl lance-spark-3.5_2.12 -am — 1238 tests, 0 failures, 0 errors.

Fixes lance-format#712.

StagedCommit captures storage options once at stage-create time from
the catalog's static config. For path-based staged creates/replaces
(no namespace), that is the only storage-options source available at
that point, so write-time `.option(...)` values and namespace-vended
credentials obtained afterward were silently dropped from the final
manifest commit, falling back to ambient credential discovery instead.

LanceBatchWrite.commit() now merges writeOptions.getStorageOptions()
and initialStorageOptions into the StagedCommit before it commits,
mirroring the merge the non-staged branch already performs and the
merge LanceSparkWriteOptions.toWriteParams() already performs for
executor-side fragment writes.

StagedCommit also now defensively copies its storage options map at
construction time, since callers (e.g. the catalog's static config)
may hand it an unmodifiable map.
@github-actions github-actions Bot added the bug Something isn't working label Jul 22, 2026
Some comments overstated when StagedCommit only has the catalog's
static options (true for path-based staged creates, not namespace-based
ones), referenced a commit call that doesn't happen in that method, and
used a term ("ambient credential discovery") that appears nowhere else
in the codebase. Others named specific call sites that don't actually
exercise the scenario they claimed to simulate. Trimmed to state only
what's accurate and load-bearing.
@ivscheianu

Copy link
Copy Markdown
Contributor Author

Hello @hamersaw, small one. I'd appreciate it if you could have a look when you get a chance. Thanks a lot!

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

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CREATE/REPLACE (staged) commits drop write-time storage options

1 participant