{"record":{"id":"b6fed7a5491451da","repo":"phalcon/cphalcon","slug":"extension-must-be-a-string","errorCode":null,"errorMessage":"'extension' must be a string","messagePattern":"'extension' must be a string","errorType":"exception","errorClass":"Phalcon\\Mvc\\View\\Engine\\Volt\\Exceptions\\InvalidOptionType","httpStatus":null,"severity":"error","filePath":"phalcon/Mvc/View/Engine/Volt/Compiler.zep","lineNumber":406,"sourceCode":"            throw new InvalidOptionType(\"separator\", \"string\");\n        }\n\n        /**\n         * By default the compile extension is .php\n         */\n        if !fetch compiledExtension, options[\"extension\"] {\n            if fetch compiledExtension, options[\"compiledExtension\"] {\n                trigger_error(\n                    \"The 'compiledExtension' option is deprecated. Use 'extension' instead.\",\n                    E_USER_DEPRECATED\n                );\n            } else {\n                let compiledExtension = \".php\";\n            }\n        }\n\n        if unlikely typeof compiledExtension != \"string\" {\n            throw new InvalidOptionType(\"extension\", \"string\");\n        }\n\n        /**\n         * Stat option assumes the compilation of the file\n         */\n        if !fetch stat, options[\"stat\"] {\n            let stat = true;\n        }\n\n        /**\n         * Check if there is a compiled path\n         */\n        if typeof compiledPath == \"string\" {\n            /**\n             * Calculate the template realpath's\n             */\n            if !empty compiledPath {\n                /**","sourceCodeStart":388,"sourceCodeEnd":424,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/Mvc/View/Engine/Volt/Compiler.zep#L388-L424","documentation":"The Volt 'extension' option (deprecated alias 'compiledExtension') sets the file extension appended to compiled templates — default '.php' — and must be a string; any other type throws InvalidOptionType('extension', 'string') at phalcon/Mvc/View/Engine/Volt/Compiler.zep:406. Note this is the compiled-file extension, not the template source extension.","triggerScenarios":"setOptions(['extension' => '.php']) is fine, but setOptions(['extension' => null]) or an array throws; option arrays built from user/config input without normalization; deprecated 'compiledExtension' key with a non-string value after a Phalcon 5 upgrade.","commonSituations":"Config-driven Volt options where the key exists but is empty/null; mixing up 'extension' (compiled file) with engine-registration keys like '.volt'; JSON/YAML sources yielding non-string scalars.","solutions":["Omit the key to keep the '.php' default, or pass an explicit string including the leading dot","Cast where the value may be numeric/nullable: 'extension' => (string) $value","Sanitize the entire options array (always/prefix/separator/extension/path/stat) in one place before setOptions()"],"exampleFix":"// before\n$volt->setOptions(['extension' => $config->volt->compiledExtension]); // null\n\n// after\n$volt->setOptions(['extension' => (string) $config->path('volt.compiledExtension', '.php')]);","handlingStrategy":"validation","validationCode":"if (isset($options['extension']) && !is_string($options['extension'])) {\n    $options['extension'] = (string) $options['extension'];\n}","typeGuard":"function isVoltExtensionOptionValid(mixed $ext): bool\n{\n    return !isset($ext) || is_string($ext);\n}","tryCatchPattern":null,"preventionTips":["Remember 'extension' = compiled file extension, default .php","Cast nullable config values or drop the key","Sanitize always/prefix/separator/extension/path/stat together"],"tags":["phalcon","volt","compiler","options","type-validation"],"backgroundTag":"config-type-mismatch","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}