can1357/oh-my-pi · error · Error

hit_count must be >= 0, got ${hitCount}

Error message

hit_count must be >= 0, got ${hitCount}

What it means

recordTierHits rejects negative hit counts because a count of hits cannot logically be below zero; doing so would corrupt cumulative statistics (totalHits, callsWithHits).

Source

Thrown at packages/mnemopi/src/core/recall-diagnostics.ts:69

	constructor() {
		this.tierStats = newTierStats();
		this.totalCalls = 0;
		this.callsUsingWmFallback = 0;
		this.callsUsingEmFallback = 0;
		this.callsTrulyEmpty = 0;
		this.createdAt = new Date().toISOString();
	}

	private static validateTier(tier: string): asserts tier is RecallTier {
		if (!isRecallTier(tier)) {
			throw new Error(`unknown recall tier ${JSON.stringify(tier)}; valid tiers: ${JSON.stringify(RECALL_TIERS)}`);
		}
	}

	recordTierHits(tier: RecallTier | string, hitCount: number): void {
		RecallDiagnostics.validateTier(tier);
		if (hitCount < 0) throw new Error(`hit_count must be >= 0, got ${hitCount}`);
		const stats = this.tierStats[tier];
		if (hitCount > 0) stats.callsWithHits++;
		stats.totalHits += hitCount;
	}
	recordFallbackUsed(options: { readonly wm?: boolean; readonly em?: boolean } = {}): void {
		if (options.wm === true) this.callsUsingWmFallback++;
		if (options.em === true) this.callsUsingEmFallback++;
	}
	recordCall(options: { readonly trulyEmpty?: boolean; readonly truly_empty?: boolean } = {}): void {
		this.totalCalls++;
		if (options.trulyEmpty === true || options.truly_empty === true) this.callsTrulyEmpty++;
	}
	fallbackRate(): { readonly wm: number; readonly em: number } {
		if (this.totalCalls === 0) return { wm: 0.0, em: 0.0 };
		return {
			wm: Math.min(1.0, this.callsUsingWmFallback / this.totalCalls),
			em: Math.min(1.0, this.callsUsingEmFallback / this.totalCalls),
		};

View on GitHub (pinned to 9690622007)

Solutions

  1. Clamp negative values to 0 before recording: Math.max(0, hitCount)
  2. Fix the upstream computation that produced a negative count
  3. Skip recording when the computed count is negative and log the anomaly

Example fix

// before
diag.recordTierHits(tier, after - before); // may be negative
// after
diag.recordTierHits(tier, Math.max(0, after - before));
Defensive patterns

Strategy: validation

Validate before calling

if (Number.isInteger(hitCount) && hitCount >= 0) {
  diag.recordTierHits(tier, hitCount);
}

Try / catch

try {
  diag.recordTierHits(tier, hitCount);
} catch (err) {
  if (err instanceof Error && err.message.includes("hit_count must be >= 0")) {
    logger.warn("negative hit count computed; clamping to 0", { tier, hitCount });
    diag.recordTierHits(tier, 0);
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling recordTierHits(tier, -1) — typically from subtracting counters or an arithmetic bug producing negative deltas.

Common situations: Computing hit counts as `after - before` when counters reset between reads; aggregating external stats that already normalized negatives to zero elsewhere; integer underflow in custom scoring.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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