phalcon/cphalcon · error · Phalcon\Container\Exceptions\CircularAliasFound

Circular alias detected: '{alias}'

Error message

Circular alias detected: '{alias}'

What it means

setAlias(name, alias) walks the existing alias chain starting from the target to verify the new alias cannot loop back onto itself; CircularAliasFound is thrown when following the chain returns to the new alias. Cycles are rejected because alias resolution would never terminate.

Source

Thrown at phalcon/Container/Container.zep:665

    /**
     * Detect circular aliases
     *
     * @param string $alias
     * @param string $target
     *
     * @return void
     * @throws CircularAliasFound
     */
    private function detectCircularAlias(string alias, string target) -> void
    {
        var current, seen;

        let current = target;
        let seen    = [];

        while (true) {
            if (current === alias) {
                throw new CircularAliasFound(alias);
            }

            if (array_key_exists(current, seen)) {
                break;
            }

            if (!array_key_exists(current, this->aliases)) {
                break;
            }

            let seen[current] = true;
            let current       = this->aliases[current];
        }
    }

    /**
     * Locate a processor
     *

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Keep aliases one-directional — every alias chain must terminate at a real registered service name
  2. Remove the old reverse mapping before adding a new alias in the opposite direction (rebuild the alias set cleanly)
  3. Sketch or assert the chain before registering; check with hasAlias() to catch duplicates
  4. Never self-alias: setAlias('x', 'x') is always a cycle

Example fix

// before
$c->setAlias('db', 'database');
$c->setAlias('database', 'db'); // CircularAliasFound

// after
$c->set('db', Pdo\Connection::class);
$c->setAlias('db', 'database'); // database -> db (terminates)
Defensive patterns

Strategy: validation

Validate before calling

// Pre-validate that adding alias -> target keeps the graph acyclic
function aliasWouldCycle(array $aliases, string $alias, string $target): bool
{
    $current = $target;
    while (isset($aliases[$current])) {
        if ($current === $alias) {
            return true;
        }
        $current = $aliases[$current];
    }
    return false;
}

if (!aliasWouldCycle($aliasMap, 'database', 'db')) {
    $container->setAlias('db', 'database');
}

Try / catch

use Phalcon\Container\Exceptions\CircularAliasFound;

try {
    $container->setAlias('database', 'db');
} catch (CircularAliasFound $e) {
    // log and abort bootstrap: alias chain loops, fix the mapping table
}

Prevention

When it happens

Trigger: setAlias('db', 'database') followed by setAlias('database', 'db') (two-way alias); longer cycles a->b->c->a introduced one link at a time; a self-alias setAlias('db', 'db').

Common situations: Two modules each registering a friendly name that points at the other; copy-pasted alias setup where direction was flipped; refactors that add a reverse alias without removing the old one.

Related errors


AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21). Data as JSON: /api/errors/6fd4322cb3d0bd48. Report an issue: GitHub.