twigphp/Twig · error · LoaderError
Looks like you try to load a template outside configured…
Error message
Looks like you try to load a template outside configured directories (%s).
What it means
FilesystemLoader resolves template names relative to configured root directories while forbidding traversal above them (via "../" segments tracked as a level counter in validateName). If the normalized path walks out of every root, Twig throws this LoaderError to prevent reading arbitrary files outside the template directories.
Solutions
- Reject or sanitize template names containing ".." segments before passing them to the loader.
- Ensure the loader root(s) are set correctly (new FilesystemLoader($rootDir), addPath()) so relative names resolve inside the project.
- Whitelist template names (regex or fixed set) instead of accepting raw input.
- If a legitimate template lives outside the root, register its directory with addPath() instead of using "../" in names.
- As defense in depth, use the sandbox extension when templates are user-influenced.
Example fix
// before
$page = $_GET['page']; // "../../etc/passwd"
echo $twig->render($page . '.twig');
// after
$page = basename((string) $_GET['page']); // strip traversal
if (!preg_match('/^[\w\-]+$/', $page)) {
throw new InvalidArgumentException('Invalid page.');
}
echo $twig->render($page . '.twig'); Defensive patterns
Strategy: validation
Validate before calling
function isTemplateInsideRoots(string $name): bool {
$name = ltrim(str_replace('\\', '/', $name), '/');
$level = 0;
foreach (explode('/', $name) as $part) {
if ($part === '..') { $level--; }
elseif ($part !== '.') { $level++; }
if ($level < 0) { return false; }
}
return true;
} Try / catch
try {
$html = $twig->render($name);
} catch (\Twig\Error\LoaderError $e) {
if (str_contains($e->getMessage(), 'outside configured directories')) {
// treat as forbidden path; log and return 404
}
throw $e;
} Prevention
- Normalize and reject ".." segments in template names before loading.
- Configure loader roots correctly via the constructor/addPath() and never use ".." in names.
- Whitelist allowed template names for user-facing rendering.
- Use the sandbox extension when rendering user-influenced templates.
When it happens
Trigger: Calling findTemplate (via render/load/getSourceContext) with a name whose normalized path escapes the loader roots, e.g. "../../etc/passwd" or "../secrets.html.twig" — typically when the name comes from user input.
Common situations: Path traversal attacks on template-name parameters; dynamic template paths miscomputed with a leading ".."; misconfigured loader roots so legitimate relative paths appear to escape.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- A template name cannot contain NUL bytes.
- Template " " is not defined.
- The "html_classes" function argument
- Block " " on template " " does not exist.
- Unable to find one of the following templates
AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13).
Data as JSON: /api/errors/dcd18f2f3db04db3.
Report an issue: GitHub.
Appendix: source
Thrown at src/Loader/FilesystemLoader.php:275
private function validateName(string $name): void
{
if (str_contains($name, "\0")) {
throw new LoaderError('A template name cannot contain NUL bytes.');
}
$name = ltrim($name, '/');
$parts = explode('/', $name);
$level = 0;
foreach ($parts as $part) {
if ('..' === $part) {
--$level;
} elseif ('.' !== $part) {
++$level;
}
if ($level < 0) {
throw new LoaderError(\sprintf('Looks like you try to load a template outside configured directories (%s).', $name));
}
}
}
private function isAbsolutePath(string $file): bool
{
return strspn($file, '/\\', 0, 1)
|| (\strlen($file) > 3 && ctype_alpha($file[0])
&& ':' === $file[1]
&& strspn($file, '/\\', 2, 1)
)
|| null !== parse_url($file, \PHP_URL_SCHEME)
;
}
}
View on GitHub (pinned to a414c3a491)