fix: warn and clamp LANCE_INITIAL_UPLOAD_SIZE instead of panicking#6389
fix: warn and clamp LANCE_INITIAL_UPLOAD_SIZE instead of panicking#6389LuciferYang wants to merge 3 commits intolance-format:mainfrom
Conversation
Setting LANCE_INITIAL_UPLOAD_SIZE to an out-of-range value (<5MB or >5GB) previously crashed the process with panic!(). Now returns an error from ObjectWriter::new(), letting callers handle it gracefully. - Change initial_upload_size() return type from usize to Result<usize> - Cache Result<usize, String> in OnceLock (lance_core::Error is not Clone) - Store validated upload_size in ObjectWriter struct to avoid repeated OnceLock access and eliminate .expect() in next_part_buffer() - Preserve silent fallback to default for non-numeric values, consistent with sibling env vars (LANCE_UPLOAD_CONCURRENCY, LANCE_CONN_RESET_RETRIES) - Extract MAX_UPLOAD_PART_SIZE constant for the 5GB upper bound
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
rust/lance-io/src/object_writer.rs
Outdated
| /// Maximum part size in GCS and S3: 5GB. | ||
| const MAX_UPLOAD_PART_SIZE: usize = 1024 * 1024 * 1024 * 5; | ||
|
|
||
| fn initial_upload_size() -> Result<usize> { |
There was a problem hiding this comment.
suggestion: What do you think of issuing a warning if the variable is misconfigured, and resetting to some reasonable default or clipping to value as needed? That way we don't need to thread the error handling carefully elsewhere. You would have to make sure you only issued the warning once, or once every few seconds, as doing it every time would be annoying.
There was a problem hiding this comment.
Good call — done in a47f8ec. Switched initial_upload_size() back to -> usize and now clamps to [5MB, 5GB] with a single tracing::warn! emitting requested and clamped fields. The existing OnceLock cache gives us the "warn once per process" guarantee for free, so no separate rate-limiter needed.
Also extracted the clamp/was-clamped logic into a pure clamp_initial_upload_size helper and added boundary unit tests (below min, min/max boundaries, in-range, above max, usize::MAX). Behavior is now consistent with the sibling env vars (LANCE_UPLOAD_CONCURRENCY, LANCE_CONN_RESET_RETRIES) that fall back silently on bad input.
Per review feedback on lance-format#6389: an out-of-range perf-tuning env var shouldn't fail writes. Clamp the value to the valid [5MB, 5GB] range and emit a tracing::warn! once (the existing OnceLock cache guarantees the warning fires at most once per process). This also matches the silent-fallback behavior of the sibling env vars LANCE_UPLOAD_CONCURRENCY and LANCE_CONN_RESET_RETRIES.
Extract the clamp logic into a pure helper so the boundary policy ([5MB, 5GB]) and was_clamped signal can be unit-tested without fighting the OnceLock cache in initial_upload_size().
Summary
panic!()ininitial_upload_size()with a warn-and-clamp fallback whenLANCE_INITIAL_UPLOAD_SIZEis set outside the valid[5MB, 5GB]range, so misconfiguration can't crash the processMAX_UPLOAD_PART_SIZEconstant for the 5GB upper boundclamp_initial_upload_sizeas a pure helper and add boundary unit testsMotivation
Setting
LANCE_INITIAL_UPLOAD_SIZEto a value outside the valid range previously crashed the entire process viapanic!()— a disproportionate response to a perf-tuning env var misconfiguration. Per review feedback (#6389 (comment)), a crash (or even a propagatedResult) forces every caller to handle a purely operator-side mistake. Clamping to the valid range and emitting a single warning lets the workload proceed and surfaces the misconfiguration to operators. This also matches the silent-fallback behavior of the sibling env varsLANCE_UPLOAD_CONCURRENCYandLANCE_CONN_RESET_RETRIES.What Changed
initial_upload_size(): Return type staysusize. Out-of-range values are clamped into[5MB, 5GB]and a singletracing::warn!is emitted withrequestedandclampedfields. The existingOnceLockcache guarantees the warning fires at most once per process, so no separate rate-limiting logic is needed. Non-numeric and unset values continue to fall back silently to the 5MB default.clamp_initial_upload_size(raw) -> (usize, bool): Pure helper extracted for testability. Returns the clamped value and whether clamping occurred.MAX_UPLOAD_PART_SIZE: New constant for the 5GB upper bound.Behavioral Equivalence
"abc")[5MB, 5GB]< 5MBpanic!()warn!(once)> 5GBpanic!()warn!(once)No API changes —
ObjectWriter::new()signature is unchanged.Test plan
usize::MAXcargo test -p lance-io --lib object_writer— 7 tests passcargo clippy -p lance-io --tests -- -D warnings— cleancargo fmt -p lance-io -- --check— cleancargo check --workspace --tests— full workspace compiles