What happened?
Description
When running the Craft CMS 6 Alpha on a Windows development environment (like Laragon, XAMPP, or Herd for Windows), navigating to any Control Panel route (such as /admin/login) results in a TemplateLoaderException stating Unable to find the template.
The issue stems from CraftCms\Cms\View\TwigEngine::get(). The engine attempts to extract the relative template name from the absolute file path by stripping out the base templates path. On Windows, $path (provided by Laravel's View Factory) and the result of TemplateMode::get()->templatesPath() often have mismatched directory separators (forward slashes vs. backslashes) or mismatched drive letter casing (C: vs c:). Because TemplateMode::get()->templatesPath() is not normalized before being passed to Str::after, the string extraction silently fails, keeping the full absolute path. The absolute path gets passed into the Twig loader, which prepends the base path again, causing the file lookup to fail.
Steps to reproduce
- Set up a local development environment on Windows (e.g., Laragon).
- Install Craft CMS 6 Alpha.
- Attempt to visit any Control Panel route that renders a Twig template, such as
/admin/login.
- The application crashes with a
TemplateLoaderException looking for an impossible, recursively nested absolute path (e.g., C:\...\templates\C:\...\templates\login.twig).
Expected behavior
The TwigEngine should correctly normalize paths regardless of the OS directory separators and drive letter casing. The relative template name should be successfully extracted, and the Control Panel page should render normally without throwing a TemplateLoaderException.
Actual behavior
A 500 Internal Server Error is thrown with the following exception:
CraftCms\Cms\Twig\Exceptions\TemplateLoaderException
Unable to find the template "C:\...\vendor\craftcms\cms\resources\templates\login.twig".
Even though the file physically exists at that exact path, the Twig loader fails to resolve it due to the un-normalized paths in TwigEngine::get().
Proposed Fix (vendor/craftcms/cms/src/View/TwigEngine.php):
public function get($path, array $data = []): string
{
$normalizedPath = \CraftCms\Cms\Support\File::normalizePath($path);
$normalizedTemplatesPath = \CraftCms\Cms\Support\File::normalizePath(\CraftCms\Cms\View\TemplateMode::get()->templatesPath());
$template = \Illuminate\Support\Str::after($normalizedPath, $normalizedTemplatesPath);
// Fallback for Windows where drive letter casing might differ (C: vs c:)
if ($template === $normalizedPath) {
$template = \Illuminate\Support\Str::after(strtolower($normalizedPath), strtolower($normalizedTemplatesPath));
}
try {
return $this->renderer->renderPageTemplate($template, $data);
// ...
Craft CMS version
6.0.0
PHP version
8.5.6
Operating system and version
Microsoft Windows 10 Pro (Version 10.0.19045)
Database type and version
MySQL 8.4.3
Image driver and version
No response
Installed plugins and versions
What happened?
Description
When running the Craft CMS 6 Alpha on a Windows development environment (like Laragon, XAMPP, or Herd for Windows), navigating to any Control Panel route (such as
/admin/login) results in aTemplateLoaderExceptionstatingUnable to find the template.The issue stems from
CraftCms\Cms\View\TwigEngine::get(). The engine attempts to extract the relative template name from the absolute file path by stripping out the base templates path. On Windows,$path(provided by Laravel's View Factory) and the result ofTemplateMode::get()->templatesPath()often have mismatched directory separators (forward slashes vs. backslashes) or mismatched drive letter casing (C:vsc:). BecauseTemplateMode::get()->templatesPath()is not normalized before being passed toStr::after, the string extraction silently fails, keeping the full absolute path. The absolute path gets passed into the Twig loader, which prepends the base path again, causing the file lookup to fail.Steps to reproduce
/admin/login.TemplateLoaderExceptionlooking for an impossible, recursively nested absolute path (e.g.,C:\...\templates\C:\...\templates\login.twig).Expected behavior
The
TwigEngineshould correctly normalize paths regardless of the OS directory separators and drive letter casing. The relative template name should be successfully extracted, and the Control Panel page should render normally without throwing aTemplateLoaderException.Actual behavior
A 500 Internal Server Error is thrown with the following exception:
Even though the file physically exists at that exact path, the Twig loader fails to resolve it due to the un-normalized paths in
TwigEngine::get().Proposed Fix (
vendor/craftcms/cms/src/View/TwigEngine.php):Craft CMS version
6.0.0
PHP version
8.5.6
Operating system and version
Microsoft Windows 10 Pro (Version 10.0.19045)
Database type and version
MySQL 8.4.3
Image driver and version
No response
Installed plugins and versions