twigphp/Twig · error · LoaderError

Malformed namespaced template name

Error message

Malformed namespaced template name "%s" (expecting "@namespace/template_name").

What it means

Namespaced template names must follow '@namespace/template_name'. parseName() throws this when a name starts with '@' but contains no '/', so no namespace separator can be found. The default (main) namespace requires no '@' prefix.

Solutions

  1. Use the full '@namespace/template' form, e.g. '@Blog/post.html.twig'.
  2. If the template is in the main namespace, drop the '@' prefix entirely.
  3. Sanitize/dynamically constructed names: ensure the '/separator and non-empty shortname exist before rendering.

Example fix

// before
$twig->render('@Blog'.$page); // '@Blogabout' — no slash
// after
$twig->render('@Blog/'.$page.'.html.twig');
Defensive patterns

Strategy: validation

Validate before calling

if (str_starts_with($name, '@') && !str_contains($name, '/')) { throw new \InvalidArgumentException("Template name '$name' must be '@ns/template'"); }

Type guard

function isWellFormedNamespacedName(string $name): bool { return !(str_starts_with($name, '@') && !str_contains($name, '/')); }

Try / catch

try { $twig->render($name); } catch (Twig\Error\LoaderError $e) { if (str_contains($e->getMessage(), 'Malformed namespaced')) { // fix name format or drop '@' for main namespace } }

Prevention

When it happens

Trigger: Passing a name like '@Blog' (missing '/shortname') to any template lookup; programmatically building names with an empty shortname; concatenating variables into template names incorrectly.

Common situations: Dynamic template name construction where a variable is empty; user-supplied template names lacking the namespace separator; confusing the '@' syntax with directory paths.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13). Data as JSON: /api/errors/851f5add7e7e217f. Report an issue: GitHub.

Appendix: source

Thrown at src/Loader/FilesystemLoader.php:246

        $this->errorCache[$name] = \sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace]));

        if (!$throw) {
            return null;
        }

        throw new LoaderError($this->errorCache[$name]);
    }

    private function normalizeName(string $name): string
    {
        return preg_replace('#/{2,}#', '/', str_replace('\\', '/', $name));
    }

    private function parseName(string $name, string $default = self::MAIN_NAMESPACE): array
    {
        if (isset($name[0]) && '@' == $name[0]) {
            if (false === $pos = strpos($name, '/')) {
                throw new LoaderError(\sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
            }

            $namespace = substr($name, 1, $pos - 1);
            $shortname = substr($name, $pos + 1);

            return [$namespace, $shortname];
        }

        return [$default, $name];
    }

    private function validateName(string $name): void
    {
        if (str_contains($name, "\0")) {
            throw new LoaderError('A template name cannot contain NUL bytes.');
        }

        $name = ltrim($name, '/');

View on GitHub (pinned to a414c3a491)