{"record":{"id":"96ddfb0dac57ef57","repo":"phalcon/cphalcon","slug":"invalid-template-engine-registration-for-extension","errorCode":null,"errorMessage":"Invalid template engine registration for extension: {extension}","messagePattern":"Invalid template engine registration for extension: (.+?)","errorType":"exception","errorClass":"Phalcon\\Mvc\\View\\Exceptions\\InvalidEngineRegistration","httpStatus":null,"severity":"error","filePath":"phalcon/Mvc/View.zep","lineNumber":1334,"sourceCode":"                        if engineService instanceof Closure {\n                            let engineService = Closure::bind(\n                                engineService,\n                                di\n                            );\n\n                            let engines[extension] = call_user_func(\n                                engineService,\n                                this\n                            );\n                        } else {\n                            let engines[extension] = engineService;\n                        }\n                    } else {\n                        /**\n                         * Engine can be a string representing a service in the DI\n                         */\n                        if typeof engineService != \"string\" {\n                            throw new InvalidEngineRegistration(extension);\n                        }\n\n                        let engines[extension] = di->get(\n                            engineService,\n                            [this]\n                        );\n                    }\n                }\n            }\n\n            let this->engines = engines;\n        }\n\n        return engines;\n    }\n}\n","sourceCodeStart":1316,"sourceCodeEnd":1351,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/Mvc/View.zep#L1316-L1351","documentation":"Each registered engine entry may be an object (typically a Closure receiving the view, or a pre-built engine instance) or a string naming a DI service resolved via di->get($engineService, [$view]) — anything else (int, null, array, bool) throws InvalidEngineRegistration at phalcon/Mvc/View.zep:1334, because there is no way to turn that value into a rendering engine.","triggerScenarios":"registerEngines(['.volt' => null]) from an unset variable; registerEngines(['.phtml' => ['class' => PhpEngine::class]]) passing a config array instead of a string or closure; entries sourced from decoded JSON config with wrong types.","commonSituations":"Copy-pasting engine config from documentation into an array-shaped config file and passing it verbatim; conditional engine registration where one branch leaves null; PHP 8.1+ deprecation-free refactors that changed closure formatting.","solutions":["Use a Closure: '.volt' => function ($view, $di) { $volt = new \\Phalcon\\Mvc\\View\\Engine\\Volt($view, $di); ... return $volt; }","Or a service name string that the DI can resolve: '.volt' => 'voltEngine'","Or an already-constructed engine instance","array_map/validation to assert every entry is_object() || is_string() before registerEngines()"],"exampleFix":"// before\n$view->registerEngines(['.volt' => ['service' => 'voltEngine']]);\n\n// after\n$view->registerEngines(['.volt' => function ($view, $di) {\n    $volt = new \\Phalcon\\Mvc\\View\\Engine\\Volt($view, $di);\n    $volt->setOptions(['path' => cachePath('volt/')]);\n    return $volt;\n}]);","handlingStrategy":"validation","validationCode":"foreach ($engines as $ext => $def) {\n    if (!is_string($ext) || (!is_object($def) && !is_string($def))) {\n        throw new \\InvalidArgumentException(\"Invalid engine registration for {$ext}\");\n    }\n}","typeGuard":"function isValidEngineMap(array $engines): bool\n{\n    foreach ($engines as $ext => $def) {\n        if (!is_string($ext) || (!is_object($def) && !is_string($def))) {\n            return false;\n        }\n    }\n    return true;\n}","tryCatchPattern":null,"preventionTips":["Register engines as Closures or DI service-name strings only","Validate config-derived engine maps before registerEngines()","Do not pass arrays/objects-as-config into engine slots"],"tags":["phalcon","view","volt","engines","config"],"backgroundTag":"config-type-mismatch","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}