phalcon/cphalcon · error · Phalcon\Mvc\View\Engine\Volt\Exceptions\InvalidPathClosureReturn
'path' closure didn't return a valid string
Error message
'path' closure didn't return a valid string
What it means
The Volt 'path' option may be a directory string or a closure invoked as (templatePath, options, extendsMode) to compute the compiled-file location dynamically; the closure's return value must be a string, and InvalidPathClosureReturn is thrown when it is not (phalcon/Mvc/View/Engine/Volt/Compiler.zep:457) — e.g. null from a missing return, void functions, or accidental array returns. (Its sibling InvalidPathType covers a 'path' option that is neither string nor closure.)
Source
Thrown at phalcon/Mvc/View/Engine/Volt/Compiler.zep:457
if extendsMode {
let compiledTemplatePath = compiledPath . prefix . templateSepPath . compiledSeparator . "e" . compiledSeparator . compiledExtension;
} else {
let compiledTemplatePath = compiledPath . prefix . templateSepPath . compiledExtension;
}
} elseif typeof compiledPath == "object" && compiledPath instanceof Closure {
/**
* A closure can dynamically compile the path
*/
let compiledTemplatePath = call_user_func_array(
compiledPath,
[templatePath, options, extendsMode]
);
/**
* The closure must return a valid path
*/
if unlikely typeof compiledTemplatePath != "string" {
throw new InvalidPathClosureReturn();
}
} else {
throw new InvalidPathType();
}
/**
* Compile always must be used only in the development stage
*/
if !this->phpFileExists(compiledTemplatePath) || compileAlways {
/**
* The file needs to be compiled because it either does not exist or
* needs to compiled every time
*/
let compilation = this->compileFile(
templatePath,
compiledTemplatePath,
extendsMode
);View on GitHub (pinned to b7419de9cd)
Solutions
- Make every branch of the closure return a string (absolute path of the compiled file)
- Ensure parent directories exist inside the closure (mkdir recursive) and still return the path string
- Add a return-type hint or assertion: $path = ...; assert(is_string($path)); return $path;
Example fix
// before
$volt->setOptions(['path' => function ($templatePath) {
if (!is_dir($dir)) { mkdir($dir, 0777, true); } // bool returned when branch taken
}]);
// after
$volt->setOptions(['path' => function ($templatePath) {
$dir = cache_path('volt/');
if (!is_dir($dir)) { mkdir($dir, 0777, true); }
return $dir . md5($templatePath) . '.php';
}]); Defensive patterns
Strategy: validation
Validate before calling
$pathClosure = function (string $templatePath, array $options, bool $extendsMode): string {
$dir = cache_path('volt/');
if (!is_dir($dir)) { mkdir($dir, 0777, true); }
return $dir . md5($templatePath) . '.php';
};
$result = $pathClosure('x.phtml', [], false);
if (!is_string($result) || $result === '') {
throw new \LogicException('Volt path closure must return a non-empty string');
} Try / catch
use Phalcon\Mvc\View\Engine\Volt\Exceptions\InvalidPathClosureReturn;
// The throw happens at compile time inside Volt; catch around rendering:
try {
$view->render('page/index');
} catch (InvalidPathClosureReturn $e) {
$logger->error('Volt path closure must return a string path');
throw $e;
} Prevention
- Give path closures an explicit ': string' return type so PHP itself enforces it
- Return the path in every branch; mkdir() results are bool, never return them
- Unit-test the closure standalone before wiring it into Volt options
When it happens
Trigger: A path closure that builds a path conditionally and forgets a return branch; returning the result of mkdir() (bool) or an array from a helper; using a function with side effects that returns void; returning null when a hash function fails.
Common situations: Per-tenant or hashed compiled paths computed in a closure; refactoring the closure to call a service whose method returns void; debugging code left in the closure that echoes instead of returns.
Related errors
- 'always' must be a bool value
- 'prefix' must be a string
- 'separator' must be a string
- 'extension' must be a string
- The extension is not valid
AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21).
Data as JSON: /api/errors/9d540983cd8f23f7.
Report an issue: GitHub.