{"record":{"id":"494b3a6337fa523d","repo":"phalcon/cphalcon","slug":"views-directory-must-be-a-string-or-an-array","errorCode":null,"errorMessage":"Views directory must be a string or an array","messagePattern":"Views directory must be a string or an array","errorType":"exception","errorClass":"Phalcon\\Mvc\\View\\Exceptions\\InvalidViewsDirType","httpStatus":null,"severity":"error","filePath":"phalcon/Mvc/View.zep","lineNumber":1125,"sourceCode":"        if merge {\n            let this->viewParams = array_merge(this->viewParams, params);\n        } else {\n            let this->viewParams = params;\n        }\n\n        return this;\n    }\n\n    /**\n     * Sets the views directory. Depending of your platform,\n     * always add a trailing slash or backslash\n     */\n    public function setViewsDir(var viewsDir) -> <static>\n    {\n        var position, directory, newViewsDir;\n\n        if typeof viewsDir !== \"string\" && typeof viewsDir !== \"array\" {\n            throw new InvalidViewsDirType();\n        }\n\n        if typeof viewsDir == \"string\" {\n            let this->viewsDirs = this->toDirSeparator(viewsDir);\n        } else {\n            let newViewsDir = [];\n\n            for position, directory in viewsDir {\n                if typeof directory != \"string\" {\n                    throw new ViewsDirItemMustBeString();\n                }\n\n                let newViewsDir[position] = this->toDirSeparator(directory);\n            }\n\n            let this->viewsDirs = newViewsDir;\n        }\n","sourceCodeStart":1107,"sourceCodeEnd":1143,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/Mvc/View.zep#L1107-L1143","documentation":"View::setViewsDir() accepts exactly a string (single directory) or an array of directories (multi-path views), and throws InvalidViewsDirType otherwise (phalcon/Mvc/View.zep:1125). Any other type — null, int, bool, object — cannot be resolved to a filesystem path, so the view renderer refuses it immediately instead of failing later at render time.","triggerScenarios":"$view->setViewsDir($config->application->viewsDir) when the config key is absent so null is passed; setViewsDir(0) or setViewsDir(false); passing an object (e.g. a Config object) instead of ->viewsDir string.","commonSituations":"Missing 'viewsDir' key in config.php (classic Phalcon INI/PHP config bootstrap); environment-specific config where one env lacks the key; refactoring config structure while view setup code still reads the old path.","solutions":["Ensure the value is a string path with a trailing directory separator, e.g. app/views/","If the key may be missing, default it: $view->setViewsDir($config->path('application.viewsDir', APP_PATH . '/views/'))","Fail fast at bootstrap with your own check if viewsDir is a hard requirement"],"exampleFix":"// before\n$view->setViewsDir($config->application->viewsDir); // null when key absent\n\n// after\n$view->setViewsDir($config->path('application.viewsDir', dirname(__DIR__) . '/views/'));","handlingStrategy":"type-guard","validationCode":"if (!is_string($viewsDir) && !is_array($viewsDir)) {\n    throw new \\InvalidArgumentException('viewsDir must be a string or array of strings');\n}","typeGuard":"function acceptsViewsDir(mixed $dir): bool\n{\n    return is_string($dir) || (is_array($dir) && array_filter($dir, 'is_string') === array_values($dir));\n}","tryCatchPattern":null,"preventionTips":["Default the config value: $config->path('application.viewsDir', $default)","Use Config::path() with a default instead of magic access that can yield null","Add a bootstrap assertion that viewsDir is set and the directory exists"],"tags":["phalcon","view","config","paths","bootstrap"],"backgroundTag":"config-type-mismatch","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}