can1357/oh-my-pi · error · Error

unknown recall tier ${JSON.stringify(tier)}; valid tiers: ${

Error message

unknown recall tier ${JSON.stringify(tier)}; valid tiers: ${JSON.stringify(RECALL_TIERS)}

What it means

RecallDiagnostics.recordTierHits accepts tier as a loose string but validates it against the known RECALL_TIERS set before recording; an unrecognized string throws a plain Error listing all valid tiers. This keeps tier statistics buckets consistent.

Source

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

	private tierStats: Record<RecallTier, TierStats>;
	private totalCalls: number;
	private callsUsingWmFallback: number;
	private callsUsingEmFallback: number;
	private callsTrulyEmpty: number;
	private createdAt: string;

	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++;
	}

View on GitHub (pinned to 9690622007)

Solutions

  1. Use the exported RecallTier constants instead of raw strings
  2. Inspect the error message's list of valid tiers and correct the tier value
  3. Validate/normalize the tier at the boundary (e.g. isRecallTier) before recording

Example fix

// before
diag.recordTierHits("vector", 2); // unknown tier
// after
import { isRecallTier } from "...";
const tier = "semantic"; // one of RECALL_TIERS
if (isRecallTier(tier)) diag.recordTierHits(tier, 2);
Defensive patterns

Strategy: type-guard

Validate before calling

import { isRecallTier, RECALL_TIERS } from "...";
if (isRecallTier(tier)) diag.recordTierHits(tier, hits);

Type guard

function isRecallTier(value: string): value is RecallTier {
  return (RECALL_TIERS as readonly string[]).includes(value);
}

Try / catch

try {
  diag.recordTierHits(tier, hits);
} catch (err) {
  if (err instanceof Error && err.message.startsWith("unknown recall tier")) {
    logger.warn("dropping diagnostics for unknown tier", { tier });
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling recordTierHits("vector", 3) or any string outside RECALL_TIERS; passing a tier name from another system's taxonomy; passing a raw DB value that has drifted from the enum.

Common situations: Typo in a tier constant; refactoring renamed a tier in one place but not in callers logging diagnostics; interop with external pipelines emitting different tier labels.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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