twigphp/Twig · error · RuntimeException

Unable to create the cache directory

Error message

Unable to create the cache directory (%s).

What it means

FilesystemCache::write() creates the cache directory with @mkdir if it is missing. If mkdir fails (and the directory still doesn't exist afterward), it means filesystem-level permission or path problems, so Twig throws this RuntimeException because compiled templates cannot be stored.

Solutions

  1. Create the cache directory manually and give the PHP user write access: mkdir -p <dir> && chown www-data:www-data <dir>.
  2. Verify the cache path in setCache() points to a writable location and is not occupied by a regular file.
  3. Check for read-only mounts or restricted sandbox filesystems and point the cache at a writable path (e.g. sys_get_temp_dir()).
  4. If the cache is not needed, disable it (don't set a filesystem cache) in dev.
  5. Check disk space with df -h.

Example fix

// before
$twig->setCache('/var/cache/twig'); // www-data cannot create /var/cache/twig

// after
$cacheDir = '/var/cache/twig';
if (!is_dir($cacheDir)) { @mkdir($cacheDir, 0775, true); }
if (!is_dir($cacheDir) || !is_writable($cacheDir)) {
    $cacheDir = sys_get_temp_dir().'/twig';
}
$twig->setCache($cacheDir);
Defensive patterns

Strategy: try-catch

Validate before calling

function ensureCacheDirWritable(string $cacheDir): void {
    if (!is_dir($cacheDir)) { @mkdir($cacheDir, 0775, true); }
    if (!is_dir($cacheDir) || !is_writable($cacheDir)) {
        throw new \RuntimeException("Cache dir not writable: $cacheDir");
    }
}

Try / catch

try { $twig->render($name, $vars); } catch (\RuntimeException $e) {
    if (str_starts_with($e->getMessage(), 'Unable to create the cache directory')) {
        $twig->setCache(sys_get_temp_dir().'/twig'); // fallback cache
    } else { throw $e; }
}

Prevention

When it happens

Trigger: Calling $env->setCache('/path') (FilesystemCache) and then rendering; the dirname of the cache key path cannot be created because a parent directory is missing/unwritable, the filesystem is read-only, or a non-directory file exists at that path. Also triggered when mkdir races and fails and the dir truly is absent.

Common situations: Deployed containers running the PHP process as a non-root user without write access to the cache path; read-only filesystems (Docker images, serverless /var restrictions); typoed cache path like /var/cache/twig where /var/cache/twig is actually a file; disk full.

Understand the failure class

Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.

Related errors


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

Appendix: source

Thrown at src/Cache/FilesystemCache.php:53

        return $this->directory.$hash[0].$hash[1].'/'.$hash.'.php';
    }

    public function load(string $key): void
    {
        if (is_file($key)) {
            @include_once $key;
        }
    }

    public function write(string $key, string $content): void
    {
        $dir = \dirname($key);
        if (!is_dir($dir)) {
            if (false === @mkdir($dir, 0777, true)) {
                clearstatcache(true, $dir);
                if (!is_dir($dir)) {
                    throw new \RuntimeException(\sprintf('Unable to create the cache directory (%s).', $dir));
                }
            }
        } elseif (!is_writable($dir)) {
            throw new \RuntimeException(\sprintf('Unable to write in the cache directory (%s).', $dir));
        }

        $tmpFile = tempnam($dir, basename($key));
        if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $key)) {
            @chmod($key, 0666 & ~umask());

            if (self::FORCE_BYTECODE_INVALIDATION == ($this->options & self::FORCE_BYTECODE_INVALIDATION)) {
                // Compile cached file into bytecode cache
                if (\function_exists('opcache_invalidate') && filter_var(\ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN)) {
                    @opcache_invalidate($key, true);
                } elseif (\function_exists('apc_compile_file')) {
                    apc_compile_file($key);
                }
            }

View on GitHub (pinned to a414c3a491)