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
- Skip or repair triples with empty components before hashing (validate each field is non-empty)
- Fix the extraction/import step so empty values don't become triples
- 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
- Filter out empty strings during extraction/import
- Don't trim values to empty and still use them — validate after trimming
- Use an explicit sentinel like "(unknown)" instead of "" for missing values
- Validate triples at ingestion, not at hashing time
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
- Provider file content hash must be a lowercase or uppercase
- SQLite query parameter 'q' cannot be empty
- Unsupported language '{value}'. Supported: {}
- Unable to infer language from file extension: {}. Specify `l
- Invalid pattern: {err}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/409139200b98165d.
Report an issue: GitHub.