neon-bindings/neon · error
>= i32::MAX
Error message
{size} >= i32::MAX What it means
`Utf8::into_small_unwrap` converts a UTF-8 buffer to a `SmallUtf8`, which is only valid when the byte length fits in an `i32` (a Node-API limitation for small strings). If `size() >= i32::MAX` (2 GiB), the conversion returns None and this method panics with the size. It is the panicking sibling of the fallible `into_small`.
Solutions
- Use the fallible `into_small()` and handle the None case instead of the `_unwrap` variant.
- Check `self.size() < i32::MAX as usize` before calling into_small_unwrap.
- Process the data in chunks (streaming read/truncate) rather than holding one >2 GiB string; `truncate()` is provided for this.
- Reduce memory pressure: if strings near 2 GiB are expected, switch the pipeline to operate on Buffers/bytes rather than JS strings.
Example fix
// before
let small = utf8.into_small_unwrap(); // panics for >= 2 GiB strings
// after
let small = match utf8.into_small() {
Some(s) => s,
None => return cx.throw_error("string exceeds 2 GiB limit"),
}; Defensive patterns
Strategy: validation
Validate before calling
// before converting, check the size bound
if utf8.size() >= i32::MAX as usize {
return cx.throw_error("string too large for SmallUtf8 (>= 2 GiB)");
}
let small = utf8.into_small_unwrap(); // now safe Type guard
fn fits_small_utf8(u: &Utf8) -> bool {
u.size() < i32::MAX as usize
} Try / catch
// prefer the fallible API and handle the None case explicitly
let small = utf8.into_small();
if small.is_none() { /* chunk or truncate the string instead */ } Prevention
- Prefer into_small() over into_small_unwrap() for untrusted sizes
- Stream or chunk very large text instead of materializing multi-GB JS strings
- Cap input sizes at the application layer before they reach string conversion
- Use truncate() when only a prefix of a huge string is needed
When it happens
Trigger: Calling `into_small_unwrap()` on a `Utf8` value whose string is 2,147,483,647 bytes or larger — e.g. reading a gigantic file into a JS string and then converting it; concatenating very large strings before conversion.
Common situations: Processing multi-gigabyte text files, logs, or serialized payloads through JS strings; string-building code that accumulates past the 2 GiB boundary before calling into_small_unwrap.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- class must be implemented for a type name
- try_catch: unexpected Err(Throw) when VM is not in a…
- The `neon::main` macro must only be used once
- Attempted to dereference a `neon::handle::Root` from the…
- Must call `into_inner` or `drop` on `neon::handle::Root`
AI-assisted analysis of neon-bindings/neon@38960e4381 (2026-09-13).
Data as JSON: /api/errors/f076758cf9d1a9bf.
Report an issue: GitHub.
Appendix: source
Thrown at crates/neon/src/types_impl/utf8.rs:50
impl<'a> Utf8<'a> {
pub fn size(&self) -> usize {
self.contents.len()
}
pub fn into_small(self) -> Option<SmallUtf8<'a>> {
if self.size() < SMALL_MAX {
Some(SmallUtf8 {
contents: self.contents,
})
} else {
None
}
}
pub fn into_small_unwrap(self) -> SmallUtf8<'a> {
let size = self.size();
self.into_small().unwrap_or_else(|| {
panic!("{size} >= i32::MAX");
})
}
pub fn truncate(self) -> SmallUtf8<'a> {
let size = self.size();
let mut contents = self.contents;
if size >= SMALL_MAX {
let s: &mut String = contents.to_mut();
s.truncate(SMALL_MAX - 3);
s.push_str("...");
}
SmallUtf8 { contents }
}
}
View on GitHub (pinned to 38960e4381)