laravel/framework · error · LogicException
Circular alias reference for [{$abstract}].
Error message
Circular alias reference for [{$abstract}]. What it means
Thrown by Container::getAlias when following the alias chain produces a cycle: while resolving aliases, the same abstract is encountered twice, indicating the alias map points back to itself transitively (A -> B -> A). Without this guard getAlias would loop infinitely.
Source
Thrown at src/Illuminate/Container/Container.php:1681
{
return $this->bindings;
}
/**
* Get the alias for an abstract if available.
*
* @param string $abstract
* @return string
*
* @throws \LogicException
*/
public function getAlias($abstract)
{
$seen = [];
while (isset($this->aliases[$abstract])) {
if (isset($seen[$abstract])) {
throw new LogicException("Circular alias reference for [{$abstract}].");
}
$seen[$abstract] = true;
$abstract = $this->aliases[$abstract];
}
return $abstract;
}
/**
* Get the extender callbacks for a given type.
*
* @param string $abstract
* @return array
*/
protected function getExtenders($abstract)
{View on GitHub (pinned to bd6b5437e6)
Solutions
- Inspect all alias() calls and break the cycle so the chain terminates at a non-aliased abstract.
- Use $container->getAlias($abstract) in a debug dump to find which abstract closes the loop.
- Register aliases in a single canonical place (e.g. one service provider) to prevent conflicting registrations.
Example fix
// before
$app->alias(Contract::class, 'payment');
$app->alias('payment', Contract::class); // back-reference
// after
$app->alias(Contract::class, 'payment');
// remove the reverse alias; resolve via either 'payment' or Contract::class Defensive patterns
Strategy: validation
Validate before calling
function aliasChainTerminates(\Illuminate\Container\Container $c, string $start, int $max = 50): bool
{
$seen = []; $cur = $start;
while (isset($c->getAliases()[$cur] ?? null) || $c->isAlias($cur)) {
if (isset($seen[$cur])) return false;
$seen[$cur] = true; $cur = $c->getAlias($cur);
if (--$max < 0) return false;
}
return true;
} Try / catch
try {
$container->getAlias($abstract);
} catch (\LogicException $e) {
if (str_contains($e->getMessage(), 'Circular alias')) {
// break the cycle by re-registering a single canonical alias
}
throw $e;
} Prevention
- Register all aliases from one config array validated for cycles.
- Avoid bidirectional alias() calls.
- Log alias registrations during boot for audit.
When it happens
Trigger: Registering $container->alias('A','B') then $container->alias('B','A'), or any sequence where aliases form a cycle; resolving any abstract that hits the cyclic chain. Note: the direct self-alias case (A->A) is caught earlier by the 'aliased to itself' guard; this catches A->B->A and longer loops.
Common situations: Programmatic alias setup from config that accidentally creates a loop; renaming classes and updating aliases in two places that now reference each other; service provider ordering producing cross-referential aliases.
Related errors
- [{$abstract}] is aliased to itself.
- Unresolvable dependency resolving [$parameter] in class {$pa
- The environment property must be set and cannot be empty.
- Method not provided.
- Unable to resolve dependency [{$parameter}] in class {$param
AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06).
Data as JSON: /data/errors/c28869605db06cbd.json.
Report an issue: GitHub.