Environment
- cuVS: 26.2 (crates.io)
- CUDA: 12.4
- GPU: T4 (sm_75)
- Rust: 1.82 (MSRV)
Problem
IndexParams setter methods return Self unconditionally. Invalid parameter
values are accepted at configuration time and only surface as an opaque CUDA
assertion inside Index::build() — after GPU memory has already been allocated
and graph construction has started.
// This compiles. It runs. It says nothing.
// ~1.8 seconds later, during Index::build():
let params = IndexParams::new()?
.set_graph_degree(0) // graph_degree=0 is invalid for CAGRA
.set_intermediate_graph_degree(0) // must be >= graph_degree
.set_nn_descent_niter(0); // must be > 0 for convergence
// Error surfaces here:
// cuvsError { code: CUVS_ERROR, text: "raft::exception: assertion failed" }
// No field name. No valid range. No hint.
let _index = Index::build(&res, ¶ms, &dataset)?;
The same problem affects SearchParams (set_hashmap_max_fill_rate(1.5),
set_team_size(7)) and IndexParams for ivf_pq, ivf_flat, and vamana.
When CAGRA parameters are loaded from a config file at runtime, a
misconfiguration blocks the GPU thread for the full build duration before
producing an error that names neither the offending field nor its valid range.
Root Cause
The C API (cuvsCagraBuild) validates parameters on entry and returns
CUVS_ERROR on failure. The Rust bindings expose setters that write directly
to the FFI struct without pre-validation, so constraints documented in the C
header are invisible to callers until Index::build() fires.
Proposed Fix
Add IndexParams::builder() — a parallel, additive entry point that validates
all parameters in a single build() -> Result<IndexParams> call before any
FFI allocation occurs. Existing IndexParams::new()?.set_graph_degree(...) is
unchanged.
pub struct IndexParamsBuilder { /* private */ }
impl IndexParamsBuilder {
pub fn graph_degree(mut self, v: usize) -> Self;
pub fn intermediate_graph_degree(mut self, v: usize) -> Self;
pub fn nn_descent_niter(mut self, v: usize) -> Self;
// ... remaining fields
/// Validate parameters in pure Rust (no GPU needed).
pub fn validate(&self) -> Result<()>;
/// Validate all parameters and allocate the FFI struct.
///
/// Returns `Err` with a message naming the offending field and its valid
/// range before any GPU work begins.
pub fn build(self) -> Result<IndexParams>;
}
impl IndexParams {
pub fn builder() -> IndexParamsBuilder;
}
Usage:
let params = IndexParams::builder()
.graph_degree(32)
.intermediate_graph_degree(64)
.nn_descent_niter(20)
.build()?;
// Err("graph_degree must be > 0; got 0") fires immediately,
// not 1.8s later inside Index::build()
Validation rules (derived from C header constraints):
graph_degree > 0; multiple of 32 preferred for warp alignment
intermediate_graph_degree >= graph_degree
nn_descent_niter > 0
itopk_size must be a power of 2
hashmap_max_fill_rate ∈ (0.1, 0.9)
team_size ∈ {0, 4, 8, 16, 32}
Backward Compatibility
The existing IndexParams::new() API and all setter methods are unchanged.
The builder is purely additive. No call sites break.
Scope
Rust bindings only. No C API changes required. The validation logic duplicates
constraints already enforced by the C layer — we are surfacing them earlier,
before the FFI call, with useful error messages.
A proof-of-concept implementation is available at:
https://github.com/zbennett10/cuvs/tree/feat/rust-validated-index-params-builder
Files
rust/cuvs/src/error.rs — add impl From<String> for Error
rust/cuvs/src/cagra/index_params.rs — IndexParamsBuilder
rust/cuvs/src/cagra/search_params.rs — SearchParamsBuilder
rust/cuvs/src/cagra/mod.rs — re-export builder types
- Apply same pattern to
ivf_pq, ivf_flat, vamana for consistency
Environment
Problem
IndexParamssetter methods returnSelfunconditionally. Invalid parametervalues are accepted at configuration time and only surface as an opaque CUDA
assertion inside
Index::build()— after GPU memory has already been allocatedand graph construction has started.
The same problem affects
SearchParams(set_hashmap_max_fill_rate(1.5),set_team_size(7)) andIndexParamsforivf_pq,ivf_flat, andvamana.When CAGRA parameters are loaded from a config file at runtime, a
misconfiguration blocks the GPU thread for the full build duration before
producing an error that names neither the offending field nor its valid range.
Root Cause
The C API (
cuvsCagraBuild) validates parameters on entry and returnsCUVS_ERRORon failure. The Rust bindings expose setters that write directlyto the FFI struct without pre-validation, so constraints documented in the C
header are invisible to callers until
Index::build()fires.Proposed Fix
Add
IndexParams::builder()— a parallel, additive entry point that validatesall parameters in a single
build() -> Result<IndexParams>call before anyFFI allocation occurs. Existing
IndexParams::new()?.set_graph_degree(...)isunchanged.
Usage:
Validation rules (derived from C header constraints):
graph_degree > 0; multiple of 32 preferred for warp alignmentintermediate_graph_degree >= graph_degreenn_descent_niter > 0itopk_sizemust be a power of 2hashmap_max_fill_rate∈ (0.1, 0.9)team_size∈ {0, 4, 8, 16, 32}Backward Compatibility
The existing
IndexParams::new()API and all setter methods are unchanged.The builder is purely additive. No call sites break.
Scope
Rust bindings only. No C API changes required. The validation logic duplicates
constraints already enforced by the C layer — we are surfacing them earlier,
before the FFI call, with useful error messages.
A proof-of-concept implementation is available at:
https://github.com/zbennett10/cuvs/tree/feat/rust-validated-index-params-builder
Files
rust/cuvs/src/error.rs— addimpl From<String> for Errorrust/cuvs/src/cagra/index_params.rs—IndexParamsBuilderrust/cuvs/src/cagra/search_params.rs—SearchParamsBuilderrust/cuvs/src/cagra/mod.rs— re-export builder typesivf_pq,ivf_flat,vamanafor consistency