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
- Clamp negative values to 0 before recording: Math.max(0, hitCount)
- Fix the upstream computation that produced a negative count
- 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
- Clamp computed deltas with Math.max(0, delta)
- Watch for counter resets when computing before/after differences
- Sanitize external metrics before recording
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
- Expected --${name} to be a positive integer, got ${value}
- Cache flags require --cache
- --alias requires --profile <name> or OMP_PROFILE
- goal token_budget must be a positive integer when provided
- objective is required when op=create
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/66dbd142580fd0fe.
Report an issue: GitHub.