Skip to content

fix(core): reject non-finite values in AimdConfig::validate - #7942

Open
LuciferYang wants to merge 2 commits into
lance-format:mainfrom
LuciferYang:fix/reject-non-finite-aimd-config
Open

fix(core): reject non-finite values in AimdConfig::validate#7942
LuciferYang wants to merge 2 commits into
lance-format:mainfrom
LuciferYang:fix/reject-non-finite-aimd-config

Conversation

@LuciferYang

Copy link
Copy Markdown
Contributor

Summary

AimdConfig::validate checks its rate fields with sign and ordering comparisons (initial_rate <= 0.0, min_rate > max_rate, decrease_factor >= 1.0, and so on). Every one of those comparisons is false for NaN, so a NaN value passes validation untouched; +inf likewise slips through on any field that has no opposing bound (max_rate, additive_increment).

These configs are user-reachable. The LANCE_AIMD_* environment variables and the equivalent storage_options keys are parsed with f64::parse, which accepts "nan", "inf", and "infinity" case-insensitively, and the parsed value flows straight into AimdConfig and then AimdController::newvalidate.

Failure mode

A non-finite rate does not fail loudly, which is what makes it worth guarding. With the default burst capacity, a NaN rate makes the token bucket refill to full on every acquire — (tokens + elapsed * NaN).min(burst) returns burst because f64::min drops the NaN — so throttling is silently disabled and the only visible symptom is a NaN leaking into rate metrics and logs. Only when the burst capacity is zero does the code reach Duration::from_secs_f64(NaN) and panic.

Change

Reject all six f64 fields up front when they are not finite, with an error naming the offending field, before the existing range checks run. This is the common chokepoint for all three ingress paths (env vars, storage options, and direct construction of the public AimdConfig), so it is more complete than validating at the parse layer.

Note for reviewers

This also rejects max_rate = f64::INFINITY, which previously passed validation and acted as an undocumented "no ceiling" alias. The documented sentinel for no ceiling is max_rate = 0.0, which is finite and unaffected. No code, test, or configuration in the repository sets any of these fields to a non-finite value.

Test plan

Extended the test_config_validation_rejects_invalid table with a NaN case for each of the six fields plus +inf on initial_rate and max_rate. cargo test -p lance-core --lib utils::aimd and cargo test -p lance-io --lib object_store::throttle pass; cargo fmt --all and cargo clippy -p lance-core --all-targets -- -D warnings are clean.

AimdConfig::validate checked its rate fields with sign and ordering
comparisons (`<= 0.0`, `min_rate > max_rate`, etc.), all of which are
false for NaN, so a NaN or infinity slipped through. These configs are
user-reachable: the LANCE_AIMD_* env vars and storage options are parsed
with `f64::parse`, which accepts "nan"/"inf".

A non-finite rate does not fail loudly. A NaN rate makes the token
bucket refill to full on every acquire (`NaN.min(burst)` returns burst),
silently disabling throttling; only with a zero burst capacity does it
reach `Duration::from_secs_f64(NaN)` and panic.

Reject all six f64 fields up front when not finite, with an error naming
the field. This also rejects `max_rate = inf`, which previously acted as
an undocumented "no ceiling" alias; the documented sentinel for that is
`max_rate = 0.0`, which is unaffected.
@github-actions github-actions Bot added the bug Something isn't working label Jul 23, 2026
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

AIMD configuration validation now rejects NaN and infinite values for controller parameters before applying existing range checks. Parameterized tests cover non-finite inputs and expected validation messages.

Changes

AIMD validation

Layer / File(s) Summary
Finite configuration checks
rust/lance-core/src/utils/aimd.rs
AimdConfig::validate rejects non-finite configuration values with field-specific errors, documentation states the finiteness requirement, and tests cover NaN and infinity cases.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: jackye1995

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: rejecting non-finite values in AimdConfig::validate.
Description check ✅ Passed The description accurately explains the validation bug, the fix, and the test updates.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Note

Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.

🟡 Other comments (1)
rust/lance-core/src/utils/aimd.rs-350-381 (1)

350-381: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert the InvalidInput variant as well as the message.

These new cases reuse an assertion that only checks err.to_string(). A regression returning a different error variant with the same text would still pass; assert the InvalidInput variant and retain the field-specific message check.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust/lance-core/src/utils/aimd.rs` around lines 350 - 381, The new
non-finite-value cases in the AIMD configuration validation tests only compare
error text. Update the shared assertion used by these cases to also match the
expected InvalidInput variant, while retaining the existing field-specific
message checks from err.to_string().

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Other comments:
In `@rust/lance-core/src/utils/aimd.rs`:
- Around line 350-381: The new non-finite-value cases in the AIMD configuration
validation tests only compare error text. Update the shared assertion used by
these cases to also match the expected InvalidInput variant, while retaining the
existing field-specific message checks from err.to_string().

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: QUIET

Plan: Pro Plus

Run ID: 59692e68-51f0-4908-9899-2057ffccb79a

📥 Commits

Reviewing files that changed from the base of the PR and between 5b9fb81 and 50b79e3.

📒 Files selected for processing (1)
  • rust/lance-core/src/utils/aimd.rs

The validation cases only checked the error message, so a regression
returning a different error variant with the same text would still pass.
Assert `Error::InvalidInput` alongside the message in the shared test
body (covering the pre-existing cases too). Also note in the AimdConfig
doc that max_rate must be finite unless it is the 0.0 no-ceiling sentinel.

@coderabbitai coderabbitai Bot 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
rust/lance-core/src/utils/aimd.rs (1)

104-123: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Include the input type in the validation error.

The new error includes the field name and value, but not the value’s type. Add f64 so callers receive complete diagnostic context.

Suggested fix
-                    "{name} must be finite, got {value}"
+                    "{name} (f64) must be finite, got {value}"

As per coding guidelines, input-validation errors must include full context, including variable names, values, sizes, and types.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust/lance-core/src/utils/aimd.rs` around lines 104 - 123, Update the
non-finite-value validation error in the AIMD configuration validation loop to
include the input type `f64` alongside the field name and value. Preserve the
existing validation behavior and error structure in the loop over initial_rate,
min_rate, max_rate, decrease_factor, additive_increment, and throttle_threshold.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@rust/lance-core/src/utils/aimd.rs`:
- Around line 104-123: Update the non-finite-value validation error in the AIMD
configuration validation loop to include the input type `f64` alongside the
field name and value. Preserve the existing validation behavior and error
structure in the loop over initial_rate, min_rate, max_rate, decrease_factor,
additive_increment, and throttle_threshold.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: QUIET

Plan: Pro Plus

Run ID: 090ba17d-50b3-495a-9764-72d298b23476

📥 Commits

Reviewing files that changed from the base of the PR and between 50b79e3 and 932a10b.

📒 Files selected for processing (1)
  • rust/lance-core/src/utils/aimd.rs

@LuciferYang

Copy link
Copy Markdown
Contributor Author

All six fields are f64, and the field name already pinpoints which value is wrong, so (f64) adds nothing actionable: someone who set LANCE_AIMD_INITIAL_RATE=nan already knows the field and its type. It would also diverge from the other 11 validation errors in this function ("initial_rate must be positive", etc.), none of which name the type. I'd rather keep the messages uniform, so I'm leaving this as is.

@codecov

codecov Bot commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

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.

1 participant