Humanizr/Humanizer · error · InvalidOperationException
'{path}' contains a sameRenderedAs cycle at '{node}'.
Error message
'{path}' contains a sameRenderedAs cycle at '{node}'. What it means
Thrown by ResolveUnit when following a chain of sameRenderedAs references creates a cycle. The resolver maintains a HashSet of visited case/unit nodes (formatted as caseName/unitName) and throws when it cannot add a node because it was already in the resolving set.
Source
Thrown at src/Humanizer.SourceGenerators/Common/DurationCaseModels.cs:974
string caseName,
string unitName,
ImmutableArray<string> inventory,
ImmutableDictionary<string, DurationCaseRealization> realizations,
HashSet<string> resolving,
string path,
bool aliasing)
{
if (!inventory.Contains(caseName, StringComparer.Ordinal) ||
!realizations.TryGetValue(caseName, out var realization))
{
throw new InvalidOperationException(
$"'{path}' references absent case '{caseName}'.");
}
var node = $"{caseName}/{unitName}";
if (!resolving.Add(node))
{
throw new InvalidOperationException(
$"'{path}' contains a sameRenderedAs cycle at '{node}'.");
}
DurationCaseUnit result;
switch (realization.Kind)
{
case DurationCaseRealizationKind.Authored:
if (realization.Units.IsEmpty)
{
result = new DurationCaseUnit(DurationCaseUnitKind.SameAsNominative, null);
break;
}
var unit = realization.Units[unitName];
result = unit.Kind switch
{
DurationCaseRealizationKind.Authored =>
new DurationCaseUnit(DurationCaseUnitKind.Phrase, unit.Phrase),View on GitHub (pinned to ffc2b77c0f)
Solutions
- Trace the sameRenderedAs chain starting from the node reported in the error.
- Break the cycle by ensuring at least one case in the chain resolves to an authored realization (phrase, notApplicable, or unsupported) rather than another sameRenderedAs.
- Rebuild to confirm the resolver terminates.
Example fix
# before (cycle: accusative -> dative -> accusative) accusative: sameRenderedAs: dative dative: sameRenderedAs: accusative # after accusative: sameRenderedAs: nominative dative: sameRenderedAs: nominative
Defensive patterns
Strategy: validation
Validate before calling
# Detect sameRenderedAs cycles via graph traversal before building # python: build a directed graph of case -> sameRenderedAs target, detect cycles with DFS
Prevention
- Ensure every sameRenderedAs chain eventually terminates at an authored case (one with a phrase, notApplicable, or unsupported).
- Draw the alias graph on paper before encoding it in YAML.
- Prefer aliasing to nominative (the citation case) as the common terminal to avoid accidental cycles.
When it happens
Trigger: Case A's sameRenderedAs points to Case B, and Case B's sameRenderedAs points back to Case A (directly or through a longer chain), so the recursive resolution revisits a node already in the resolving set.
Common situations: A contributor sets up a group of cases to alias each other and accidentally creates a circular reference (e.g. dative -> accusative -> dative). Also occurs when a case is supposed to alias nominative but is itself aliased by nominative.
Related errors
- '{path}' references absent case '{caseName}'.
- '{path}' aliases '{node}' to a case or unit that is not appl
- '{path}' must define exactly one of phrase, sameRenderedAs,
- Case overlay '{path}.phrase' must explicitly define singular
- Duration case phrases use unsupported plural rule '{pluralRu
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/64059783a0ce9c2e.
Report an issue: GitHub.