twigphp/Twig · error · Twig\Error\RuntimeError

Failed to load Twig template

Error message

Failed to load Twig template "%s", index "%s": cache might be corrupted.

What it means

Environment::loadTemplate throws this Twig\RuntimeError after writing/reading the compiled template cache class: the eval'd compiled code did not define the expected template class ($cls). Twig treats this as evidence the on-disk compiled cache is stale, truncated, or corrupted (e.g. same cache file reused across incompatible Twig versions).

Solutions

  1. Delete the compiled template cache directory (e.g. var/cache/* or templates_c) and let Twig regenerate it.
  2. Ensure cache dir permissions are writable by the PHP user and that disk has space.
  3. Check that only one Twig major version is installed (composer why twig/twig) and that app cache was invalidated on upgrade.
  4. If concurrency is suspected, use per-process cache dirs or a locking cache implementation (Twig\Cache\FilesystemCache with proper atomic writes).
  5. If a custom cache/loader extension was written, verify the generated class name matches the one Twig expects.

Example fix

// before (deploy script leaves stale cache)
rsync -a new-code/ /var/www/app/

// after
rsync -a new-code/ /var/www/app/
rm -rf /var/www/app/var/cache/*
Defensive patterns

Strategy: try-catch

Validate before calling

// before rendering in production deploy scripts:
$cacheDir = $config['cache'];
foreach (glob($cacheDir.'/*', GLOB_ONLYDIR) as $d) { /* ensure writable */ }
if (!is_writable($cacheDir)) { throw new RuntimeException('Twig cache dir not writable: '.$cacheDir); }
// on deploy: clear cache
array_map('unlink', glob($cacheDir.'/*/*.php'));

Try / catch

try {
    $html = $twig->render('index.html.twig', $ctx);
} catch (\Twig\Error\RuntimeError $e) {
    if (str_contains($e->getMessage(), 'cache might be corrupted')) {
        foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($cacheDir, \FilesystemIterator::SKIP_DOTS)) as $f) { @unlink($f); }
        $html = $twig->render('index.html.twig', $ctx);
    } else { throw $e; }
}

Prevention

When it happens

Trigger: loadTemplate() compiled a template whose cache file already existed, eval'd it, but class_exists($cls, false) was still false. Typically: stale cache dir left by an older Twig major version, truncated cache file (disk full, concurrent write without locking), an opcode/caching layer swallowing the eval, or a custom CacheInterface writing broken PHP.

Common situations: Deploying a Twig upgrade without clearing var/cache or templates_c; multiple PHP-FPM workers racing on the same cache file; disk-full cutting the cache write short; vendor caches baked into container images with a different Twig version than runtime.

Related errors


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

Appendix: source

Thrown at src/Environment.php:424

            if (!class_exists($cls, false)) {
                $source = $this->getLoader()->getSourceContext($name);
                $content = $this->compileSource($source);
                if (!isset($this->hotCache[$name])) {
                    $this->cache->write($key, $content);
                    $this->cache->load($key);
                }

                if (!class_exists($mainCls, false)) {
                    /* Last line of defense if either $this->bcWriteCacheFile was used,
                     * $this->cache is implemented as a no-op or we have a race condition
                     * where the cache was cleared between the above calls to write to and load from
                     * the cache.
                     */
                    eval('?>'.$content);
                }

                if (!class_exists($cls, false)) {
                    throw new RuntimeError(\sprintf('Failed to load Twig template "%s", index "%s": cache might be corrupted.', $name, $index), -1, $source);
                }
            }
        }

        $this->extensionSet->initRuntime();

        return $this->loadedTemplates[$cls] = new $cls($this);
    }

    /**
     * Creates a template from source.
     *
     * This method should not be used as a generic way to load templates.
     *
     * @param string      $template The template source
     * @param string|null $name     An optional name of the template to be used in error messages
     *
     * @throws LoaderError When the template cannot be found

View on GitHub (pinned to a414c3a491)