can1357/oh-my-pi · critical · AmbiguousIdentityError
ambiguous class for `${lower}`: `${tied[0]}` and `${tied[1]}
Error message
ambiguous class for `${lower}`: `${tied[0]}` and `${tied[1]}` tie What it means
AmbiguousIdentityError from classifyRanks: two class selectors in the taxonomy match a lowercased model id with equal rank, so class classification is indeterminate. Lenient mode degrades to class "unknown"; strict mode throws, naming both tied classes. Family and revision are only extracted after a unique class winner exists.
Source
Thrown at packages/catalog/src/compat/taxonomy.ts:155
const lower = model.trim().toLowerCase();
const bare = bareOf(lower);
let winner: { rank: readonly [number, number]; cls: CompiledClass } | undefined;
let tied: readonly [string, string] | undefined;
for (const cls of rules.taxonomy.classes) {
for (const matcher of cls.matchers) {
if (!matcherMatches(matcher, lower, bare)) continue;
const rank = [MATCHER_RANK[matcher.kind], matcher.token.length] as const;
if (winner && winner.rank[0] === rank[0] && winner.rank[1] === rank[1] && winner.cls.id !== cls.id) {
tied = [winner.cls.id, cls.id];
} else if (!winner || winner.rank[0] < rank[0] || (winner.rank[0] === rank[0] && winner.rank[1] < rank[1])) {
winner = { rank, cls };
tied = undefined;
}
}
}
if (tied) {
if (lenient) return { class: "unknown" };
throw new AmbiguousIdentityError(lower, tied[0], tied[1], "class");
}
if (!winner) return { class: "unknown" };
const ranks: ClassRanks = { class: winner.cls.id };
const family = classifyFamily(winner.cls, bare, lower, lenient);
if (family !== undefined) ranks.family = family;
const revision = extractRevision(winner.cls, bare);
if (revision !== undefined) ranks.revision = revision;
return ranks;
}
function ranksInClass(classId: string, model: string, lenient: boolean): Omit<ClassRanks, "class"> {
const cls = rules.taxonomy.classes.find(candidate => candidate.id === classId);
if (!cls) return {};
const lower = model.trim().toLowerCase();
const bare = bareOf(lower);
const out: Omit<ClassRanks, "class"> = {};
const family = classifyFamily(cls, bare, lower, lenient);
if (family !== undefined) out.family = family;View on GitHub (pinned to 9690622007)
Solutions
- Differentiate the two class patterns so only one matches the colliding id.
- Add an explicit rank/priority to one class rule to break the tie.
- Regenerate via `bun run gen:compat` and verify classification of the previously ambiguous id.
Example fix
// before: "claude" and "claude-opus" classes tie on "claude-opus-4"
class "claude" { match "claude" }
// after: exclude the specific ids from the broad class
class "claude" { match "claude"; skip "claude-opus" } Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
null
Try / catch
try {
const ranks = classifyRanks(lower, /* lenient */ false);
} catch (err) {
if (err instanceof AmbiguousIdentityError && err.kind === "class") {
return { class: "unknown" };
}
throw err;
}
// or pass lenient=true to get { class: "unknown" } instead of throwing Prevention
- Use lenient mode for exploratory classification paths; strict mode in CI to catch KDL mistakes.
- Keep wildcard class patterns disjoint from specific ones via skip lists.
- Add explicit ranks to broad classes so specific ones win.
When it happens
Trigger: cls()/ranks() on a model id where two class patterns (e.g. a generic "openai" class and a specific "o-series" class) both match with the same rank and neither is more specific.
Common situations: Introducing a new class KDL rule with a pattern that also matches ids claimed by an existing class; wildcard classes catching specific ids at equal rank.
Related errors
- ambiguous family for `${model}`: `${tied[0]}` and `${tied[1]
- ambiguous overlap for `${provider}/${model}` on axis `${axis
- invalid compiled revision term in ${compiled.source}
- Model ${spec.provider}/${spec.id} resolved to an empty think
- missing reviewed collapse table for google-gemini-cli
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/37b277dab932a738.
Report an issue: GitHub.