NVIDIA / NVIDIA/cuvs

[Rust] IndexParams/SearchParams setters silently accept invalid values — add validated builder

Open
#1,859 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Cuda
Stars
854
Forks
236
Avg merge
3d 3h
Merged PRs (30d)
62

Description

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, &params, &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.rsIndexParamsBuilder
  • rust/cuvs/src/cagra/search_params.rsSearchParamsBuilder
  • rust/cuvs/src/cagra/mod.rs — re-export builder types
  • Apply same pattern to ivf_pq, ivf_flat, vamana for consistency

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with rust/cuvs/src/cagra/index_params.rs, rust/cuvs/src/cagra/search_params.rs, rust/cuvs/src/cagra/mod.rs, and rust/cuvs/src/error.rs to understand the existing setters, error type, and exports. Compare the C-header constraints listed in the issue with the CAGRA, IVF-PQ, IVF-flat, and Vamana parameter APIs. Done means additive builders validate before FFI allocation, return field-specific errors, and preserve the existing setter API.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
backend-api-design
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.