symfony/translation · error · LogicException
Circular reference detected when adding a fallback…
Error message
Circular reference detected when adding a fallback catalogue for locale "%s".
What it means
addFallbackCatalogue links a fallback catalogue under this one. Before linking, it walks the incoming catalogue's existing fallback chain; if any catalogue in that chain has the same locale as $this, linking would create a circular fallback reference, so a LogicException is thrown.
Solutions
- Break the cycle: remove the fallback link that points back to the ancestor locale before adding.
- Only chain strictly distinct locales (en -> fr -> de) when assembling fallback catalogues manually.
- Build a fresh fallback chain from configuration instead of mutating an existing catalogue graph.
- If using the Translator, let it compute fallback locales via fallbackLocales rather than wiring catalogues by hand.
Example fix
// before: en falls back to fr, which falls back to en $fr->addFallbackCatalogue($en); $en->addFallbackCatalogue($fr); // throws // after: one-directional chain $fr->addFallbackCatalogue($en);
Defensive patterns
Strategy: validation
Validate before calling
$seen = [];
for ($c = $catalogue; null !== $c; $c = $c->getFallbackCatalogue()) {
$seen[$c->getLocale()] = true;
}
if (isset($seen[$this->getLocale()])) { /* cycle detected */ } Try / catch
try {
$catalogue->addFallbackCatalogue($fallback);
} catch (\LogicException $e) {
// rebuild the fallback chain without the cycle
} Prevention
- Keep a set of locales already in the chain and refuse duplicates when wiring.
- Derive fallback chains from a flat config list instead of ad-hoc mutation.
- Prefer Translator::setFallbackLocales over manual catalogue linking.
When it happens
Trigger: Calling $a->addFallbackCatalogue($b) where $b (or any of $b's fallback ancestors) has the same locale as $a, e.g. $a('en') -> addFallbackCatalogue($b('fr')) when $b already falls back to an 'en' catalogue.
Common situations: Programmatically wiring fallback chains from config where locales cycle (en -> fr -> en); reusing the same catalogue object twice in a chain; tests replicating the translator's circular-reference detection.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Cannot add a catalogue for locale
- The Translator does not support the following options
- The file dumper needs a path option.
- Unable to create directory
- No support implemented for dumping XLIFF version
AI-assisted analysis of symfony/translation@ae9e8a51bc (2026-09-15).
Data as JSON: /api/errors/b7f0fd4c3814ad33.
Report an issue: GitHub.
Appendix: source
Thrown at MessageCatalogue.php:176
if ($catalogue instanceof MetadataAwareInterface) {
$metadata = $catalogue->getMetadata('', '');
$this->addMetadata($metadata);
}
if ($catalogue instanceof CatalogueMetadataAwareInterface) {
$catalogueMetadata = $catalogue->getCatalogueMetadata('', '');
$this->addCatalogueMetadata($catalogueMetadata);
}
}
public function addFallbackCatalogue(MessageCatalogueInterface $catalogue): void
{
// detect circular references
$c = $catalogue;
while ($c = $c->getFallbackCatalogue()) {
if ($c->getLocale() === $this->getLocale()) {
throw new LogicException(\sprintf('Circular reference detected when adding a fallback catalogue for locale "%s".', $catalogue->getLocale()));
}
}
$c = $this;
do {
if ($c->getLocale() === $catalogue->getLocale()) {
throw new LogicException(\sprintf('Circular reference detected when adding a fallback catalogue for locale "%s".', $catalogue->getLocale()));
}
foreach ($catalogue->getResources() as $resource) {
$c->addResource($resource);
}
} while ($c = $c->parent);
$catalogue->parent = $this;
$this->fallbackCatalogue = $catalogue;
foreach ($catalogue->getResources() as $resource) {View on GitHub (pinned to ae9e8a51bc)