can1357/oh-my-pi · error · Error

InvalidArg

InvalidArg

Error message

contents changed during reranking

What it means

mmr_rerank_indices takes a JS Array of strings plus parallel scores. During element extraction it reads each entry as a string; if an element is absent (not a string) at read time, it throws InvalidArg with this message. The name reflects the design assumption: contents was mutated between the length check and element access, or contains non-string entries.

Source

Thrown at crates/pi-natives/src/vectors.rs:283

pub fn mmr_rerank_indices(
	#[napi(ts_arg_type = "Array<string>")] contents: Array,
	scores: Float64Array,
	lambda_param: f64,
	top_k: u32,
) -> Result<Uint32Array> {
	if scores.len() != contents.len() as usize {
		return invalid("scores length must equal contents length");
	}
	let limit = top_k as usize;
	let count = contents.len() as usize;
	if limit == 0 || count == 0 {
		return Ok(Uint32Array::new(Vec::new()));
	}
	let mut sets = Vec::with_capacity(count);
	for index in 0..contents.len() {
		let content = contents
			.get::<JsString>(index)?
			.ok_or_else(|| Error::new(Status::InvalidArg, "contents changed during reranking"))?;
		sets.push(word_set(&js::utf8(content)?));
	}
	let mut selected: Vec<u32> = Vec::with_capacity(limit.min(count));
	selected.push(0);
	let mut remaining: Vec<u32> = (1..count as u32).collect();

	while !remaining.is_empty() && selected.len() < limit {
		let mut best_idx = 0usize;
		let mut best_score = f64::NEG_INFINITY;
		for (idx, &candidate) in remaining.iter().enumerate() {
			let mut max_similarity = 0.0f64;
			for &picked in &selected {
				let similarity = jaccard_sorted(&sets[candidate as usize], &sets[picked as usize]);
				if similarity > max_similarity {
					max_similarity = similarity;
				}
			}
			let relevance = scores[candidate as usize];

View on GitHub (pinned to 9690622007)

Solutions

  1. Ensure every element of contents is a non-null string before calling (filter/coalesce missing entries)
  2. Ensure contents.length === scores.length and the array is not mutated during the call
  3. Normalize entries: contents.map(c => typeof c === 'string' ? c : '') or filter with an index map to keep alignment
  4. Catch the InvalidArg and fall back to a JS MMR implementation

Example fix

// before
native.mmrRerankIndices(contents, scores, 0.7, 10);
// after
const clean = contents.map(c => (typeof c === 'string' ? c : ''));
if (clean.length !== scores.length) throw new Error('contents/scores length mismatch');
native.mmrRerankIndices(clean, scores, 0.7, 10);
Defensive patterns

Strategy: validation

Validate before calling

if (!Array.isArray(contents) || contents.some(c => typeof c !== 'string')) throw new TypeError('contents must be an array of strings');
if (contents.length !== scores.length) throw new Error('contents and scores must have equal length');

Type guard

const isStringArray = (a) => Array.isArray(a) && a.every(x => typeof x === 'string');

Try / catch

try {
  return native.mmrRerankIndices(contents, scores, lambda, topK);
} catch (err) {
  if (err?.code === 'InvalidArg' && String(err?.message).includes('contents changed during reranking')) {
    return jsMmrRerank(contents, scores, lambda, topK);
  } throw err;
}

Prevention

When it happens

Trigger: Calling native.mmrRerankIndices(contents, scores, lambda, topK) where contents contains null/undefined/non-string elements (including sparse array holes), or where contents is mutated concurrently while the synchronous call runs.

Common situations: Passing sparse arrays or arrays containing undefined holes; search/rerank pipelines that build the contents array incorrectly (e.g. forgetting to coalesce a missing document field); passing objects or numbers instead of strings.

Related errors


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