{"record":{"id":"9c99cdb5a0207316","repo":"twigphp/Twig","slug":"a-block-chain-cannot-contain-templates-from-different-twig","errorCode":null,"errorMessage":"A block chain cannot contain templates from different Twig environments.","messagePattern":"A block chain cannot contain templates from different Twig environments\\.","errorType":"exception","errorClass":"LogicException","httpStatus":null,"severity":"error","filePath":"src/BlockChain.php","lineNumber":54,"sourceCode":"     * @param iterable<string|TemplateWrapper> $templates Templates ordered from highest to lowest precedence\n     * @param array<string, mixed>             $context   Default variables used to resolve dynamic parent expressions\n     */\n    public function __construct(\n        private Environment $env,\n        iterable $templates,\n        private array $context = [],\n    ) {\n        foreach ($templates as $template) {\n            if (\\is_string($template)) {\n                $template = $env->load($template);\n            }\n            if (!$template instanceof TemplateWrapper) {\n                throw new \\TypeError(\\sprintf('Block chain templates must be strings or \"%s\" instances, \"%s\" given.', TemplateWrapper::class, get_debug_type($template)));\n            }\n\n            $template = $template->unwrap();\n            if (!$template->isOwnedBy($env)) {\n                throw new \\LogicException('A block chain cannot contain templates from different Twig environments.');\n            }\n\n            $this->templates[] = $template;\n        }\n\n        if (!$this->templates) {\n            throw new \\InvalidArgumentException('A block chain requires at least one template.');\n        }\n    }\n\n    /**\n     * @param array<string, mixed> $context\n     */\n    public function hasBlock(string $name, array $context = []): bool\n    {\n        $blocks = $this->fixed ? $this->blocks : $this->resolveBlocks($context + $this->context + $this->env->getGlobals());\n\n        return isset($blocks[$name]);","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/twigphp/Twig/blob/a414c3a491defb5a60f2fc88ef79ff37c90010cd/src/BlockChain.php#L36-L72","documentation":"All templates in a BlockChain must belong to the same Environment so block inheritance resolution stays consistent. After unwrapping each TemplateWrapper, the constructor checks Template::isOwnedBy($env) and throws this LogicException when a template was loaded from a different Environment instance.","triggerScenarios":"Constructing BlockChain with templates loaded via $envA->load('a.html.twig') and $envB->load('b.html.twig'), or a cached/shared template wrapper reused across two Environment instances.","commonSituations":"Multi-tenant or multi-app setups with several Twig environments sharing template files; test code mixing an isolated test Environment with the app's Environment; frameworks that register template wrappers globally.","solutions":["Load every template in the chain from the same Environment instance that is passed as $env.","Create a fresh BlockChain per Environment instead of sharing chains across them.","Trace where the mismatched wrapper came from (cache, container, static) and load it from the current Environment instead."],"exampleFix":"// before\n$chain = new \\Twig\\BlockChain($envA, [$envA->load('a.twig'), $envB->load('b.twig')]);\n// after\n$chain = new \\Twig\\BlockChain($envA, [$envA->load('a.twig'), $envA->load('b.twig')]);","handlingStrategy":"validation","validationCode":"foreach ($templates as $t) {\n    $wrapper = is_string($t) ? $env->load($t) : $t;\n    if (!$wrapper->unwrap()->isOwnedBy($env)) {\n        throw new \\LogicException('Template loaded from a different Environment.');\n    }\n}","typeGuard":"function ownedByEnv(\\Twig\\TemplateWrapper $w, \\Twig\\Environment $env): bool {\n    return $w->unwrap()->isOwnedBy($env);\n}","tryCatchPattern":"try {\n    $chain = new \\Twig\\BlockChain($env, $templates);\n} catch (\\LogicException $e) {\n    // reload all entries from $env by name before retrying\n}","preventionTips":["Keep one Environment per app/tenant and load all templates from it.","Avoid caching TemplateWrapper instances across Environment instances.","In tests, use the same Environment instance as production code paths."],"tags":["php","twig","logic-exception","environment"],"backgroundTag":"invalid-state-transition","analyzedSha":"a414c3a491defb5a60f2fc88ef79ff37c90010cd","analyzedAt":"2026-09-13T15:10:46.849Z","contentChangedAt":"2026-09-13T15:10:46.849Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}