can1357/oh-my-pi · warning · Error

spelling range start is too large

Error message

spelling range start is too large

What it means

The spelling API converts a JS-provided u32 range start to Rust's usize for NSRange. This InvalidArg error is thrown when the start offset cannot be represented as usize on the current platform. On 64-bit macOS usize is 64-bit so a u32 always fits; the error exists to keep the conversion total and is effectively unreachable in normal 64-bit builds.

Source

Thrown at crates/pi-natives/src/spelling.rs:85

	where
		T: Send + 'static,
	{
		let (reply, result) = flume::bounded(1);
		SPELLING_THREAD
			.send(Box::new(move || {
				let _ = reply.send(work());
			}))
			.map_err(|_| Error::new(Status::GenericFailure, "native spelling thread stopped"))?;
		result
			.recv_async()
			.await
			.map_err(|_| Error::new(Status::GenericFailure, "native spelling thread stopped"))?
	}

	fn ns_range(start: u32, length: u32) -> Result<NSRange> {
		Ok(NSRange {
			location: usize::try_from(start)
				.map_err(|_| Error::new(Status::InvalidArg, "spelling range start is too large"))?,
			length:   usize::try_from(length)
				.map_err(|_| Error::new(Status::InvalidArg, "spelling range length is too large"))?,
		})
	}

	pub fn check(text: &str) -> Result<Vec<SpellingRange>> {
		let checker = checker()?;
		let text = NSString::from_str(text);
		let full = NSRange { location: 0, length: text.length() };
		// `checkString:...` honors `automaticallyIdentifiesLanguages`, selecting
		// the dictionary per detected run; the legacy `checkSpellingOfString:`
		// used only the shared checker's single current language (issue #9334).
		// SAFETY: `options`/`orthography` are nil and `word_count` is null, all
		// documented as valid; the returned array is retained by objc2.
		let results = unsafe {
			checker.checkString_range_types_options_inSpellDocumentWithTag_orthography_wordCount(
				&text,
				full,

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the start offset is a valid index within the text being checked
  2. Ensure you are running a 64-bit build of the native module
  3. Clamp the range start to the text length before calling

Example fix

// before
native.checkSpelling(text, startOffset, len);
// after
const safeStart = Math.min(startOffset >>> 0, text.length);
native.checkSpelling(text, safeStart, len);
Defensive patterns

Strategy: validation

Validate before calling

if (!Number.isSafeInteger(start) || start < 0 || start > text.length) throw new RangeError('start out of range');

Type guard

const isValidStart = (s) => Number.isInteger(s) && s >= 0 && s <= 0xFFFFFFFF;

Try / catch

try {
  return await native.checkSpelling(text, start, len);
} catch (err) {
  if (String(err?.message).includes('spelling range start is too large')) {
    throw new RangeError(`spelling start ${start} rejected`);
  } throw err;
}

Prevention

When it happens

Trigger: Calling a spelling API that takes a range (e.g. checkSpelling(text, start, length)) with a start offset whose usize conversion fails — only conceivable on a 32-bit target with start near u32::MAX, or via the internal ns_range helper receiving an out-of-contract value.

Common situations: Practically never hit by developers; would appear only in 32-bit native builds or with caller-computed offsets overflowing at the u32 boundary on a 32-bit process.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/e2e21a32238df99b. Report an issue: GitHub.