fix(nodejs): reject listNamespaces limit above i32::MAX instead of wrapping (#4584)

## Summary

Fixes #4583.

`Connection::list_namespaces` narrowed `Option<u32>` to `i32` with an
unchecked `as` cast, so a JavaScript `limit` between 2^31 and 2^32 - 1
(e.g. `3000000000`) wrapped negative before reaching
`ListNamespacesRequest`. The server received a negative page size
instead of a clear client-side error.

Replaced the cast with a `checked_limit` helper using `i32::try_from`,
returning `napi::Error::from_reason` on overflow, matching the existing
`try_from` validation used for `limit` elsewhere in the same file.

## Tests

Unit tests cover the wrap case (`u32` values above `i32::MAX` reject),
the boundary (`i32::MAX` passes), and `None`/zero passthrough. `cargo
test -p lancedb-nodejs` passes 8/8 and `pnpm build` compiles the binding
and TypeScript definitions cleanly.
This commit is contained in:
Prince Jain
2026-10-22 10:45:26 -07:00
committed by GitHub
parent 55897d7c3b
commit 7f932b8552
+31 -1
View File
@@ -673,7 +673,7 @@ impl Connection {
let req = ListNamespacesRequest {
id: namespace_path,
page_token,
limit: limit.map(|l| l as i32),
limit: checked_limit(limit)?,
..Default::default()
};
let resp = self
@@ -787,3 +787,33 @@ impl Connection {
.default_error()
}
}
fn checked_limit(limit: Option<u32>) -> napi::Result<Option<i32>> {
limit
.map(i32::try_from)
.transpose()
.map_err(|_| napi::Error::from_reason("limit must not exceed 2147483647"))
}
#[cfg(test)]
mod tests {
use super::checked_limit;
#[test]
fn checked_limit_rejects_values_above_i32_max() {
// u32 values above i32::MAX wrapped negative through `as i32`,
// sending a negative page size to the server.
assert!(checked_limit(Some(3_000_000_000)).is_err());
assert!(checked_limit(Some(u32::MAX)).is_err());
}
#[test]
fn checked_limit_passes_boundary_and_missing_values() {
assert_eq!(
checked_limit(Some(i32::MAX as u32)).unwrap(),
Some(i32::MAX)
);
assert_eq!(checked_limit(Some(0)).unwrap(), Some(0));
assert_eq!(checked_limit(None).unwrap(), None);
}
}