can1357/oh-my-pi · error · RangeError

compute_fact_id: ${name} must be non-empty

Error message

compute_fact_id: ${name} must be non-empty

What it means

computeFactId also rejects empty-string components for subject, predicate, or object with a RangeError, because an empty component would collide different facts into the same hash. The check runs after the type check, so blank strings from trimmed/missing data reach this error.

Source

Thrown at packages/mnemopi/src/core/veracity-consolidation.ts:123

	} catch {
		return [];
	}
}

function nowIso(): string {
	return new Date().toISOString();
}

export function computeFactId(subject: string, predicate: string, object: string): string {
	for (const [name, value] of [
		["subject", subject],
		["predicate", predicate],
		["object", object],
	] as const) {
		if (typeof value !== "string") {
			throw new TypeError(`compute_fact_id: ${name} must be a str, got ${typeof value}`);
		}
		if (value === "") throw new RangeError(`compute_fact_id: ${name} must be non-empty`);
	}

	const chunks: Buffer[] = [];
	for (const value of [subject, predicate, object]) {
		const bytes = Buffer.from(value.normalize("NFC"), "utf8");
		chunks.push(Buffer.from(`${bytes.length}:`, "ascii"), bytes);
	}
	return `cf_${createHash("sha256").update(Buffer.concat(chunks)).digest("hex").slice(0, 24)}`;
}
export function clampVeracity(raw: unknown, context = "veracity"): Veracity {
	if (raw === null || raw === undefined) return "unknown";
	const norm = String(raw).trim().toLowerCase();
	if (norm === "") return "unknown";
	if (isVeracity(norm)) return norm;
	const rawString = String(raw);
	const rawForLog =
		rawString.length > VERACITY_WARN_VALUE_CAP
			? `${rawString.slice(0, VERACITY_WARN_VALUE_CAP)}...[truncated]`

View on GitHub (pinned to 9690622007)

Solutions

  1. Skip or repair triples with empty components before hashing (validate each field is non-empty)
  2. Fix the extraction/import step so empty values don't become triples
  3. Provide a real sentinel value if "unknown" semantics are intended, rather than ""

Example fix

// before
const id = computeFactId(s.trim(), p, o); // s may be ""
// after
if (!s.trim() || !p || !o) continue; // skip invalid triple
const id = computeFactId(s.trim(), p, o);
Defensive patterns

Strategy: validation

Validate before calling

function isValidTriple(s, p, o) {
	return [s, p, o].every(v => typeof v === "string" && v.length > 0);
}
if (!isValidTriple(s, p, o)) skipTriple();
const id = computeFactId(s, p, o);

Try / catch

try {
	const id = computeFactId(s, p, o);
} catch (err) {
	if (err instanceof RangeError && err.message.includes("non-empty")) {
		logger.warn("skipping triple with empty component", { s, p, o });
		return null;
	}
	throw err;
}

Prevention

When it happens

Trigger: computeFactId("", "knows", "bob") or any component set to ""; data rows where a field was empty in the source; .split() or regex extraction producing empty captures; over-eager trimming reducing a value to "".

Common situations: Importing sparse spreadsheet/CSV data with blank cells; extraction pipelines emitting empty matches; forms submitted with required fields blank; normalizing whitespace-only strings to "".

Related errors


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