symfony/http-foundation · error · RuntimeException

Session Storage was not able to create directory

Error message

Session Storage was not able to create directory "%s".

What it means

NativeFileSessionHandler ensures the session base directory exists; when the directory is missing, it attempts a recursive mkdir with 0777 permissions. If mkdir fails and the directory still does not exist, a RuntimeException is thrown because the handler cannot store session files.

Solutions

  1. Create the directory manually with correct ownership/permissions (e.g. mkdir -p /var/lib/php/sessions && chown www-data:www-data ...).
  2. Point session.save_path to an existing, writable directory.
  3. Grant the PHP process user write permission on the target directory's parent chain.
  4. Check that the filesystem/volume is writable (not mounted read-only) and the path is valid.

Example fix

// before
$handler = new NativeFileSessionHandler('/var/lib/php/sessions'); // dir missing, PHP user cannot create it

// after (shell pre-provisioning)
// mkdir -p /var/lib/php/sessions && chown www-data:www-data /var/lib/php/sessions
$handler = new NativeFileSessionHandler('/var/lib/php/sessions');
Defensive patterns

Strategy: try-catch

Validate before calling

$baseDir = $savePath ?? ini_get('session.save_path');
if ($baseDir && !is_dir($baseDir) && !@mkdir($baseDir, 0777, true) && !is_dir($baseDir)) {
    throw new \RuntimeException("Cannot create session dir: $baseDir");
}

Try / catch

try {
    $handler = new NativeFileSessionHandler($savePath);
} catch (\RuntimeException $e) {
    // provision the directory or switch to an alternative handler
}

Prevention

When it happens

Trigger: Constructing the handler with a $savePath (or ini session.save_path) pointing to a nonexistent directory that cannot be created — typically due to filesystem permissions, a read-only volume, or an invalid parent path.

Common situations: Deployments where /var/lib/php/sessions was removed or never created; Docker containers running as non-root with an unwritable path; misconfigured '2;/nonexistent-root/...' save paths; read-only container filesystems.

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 symfony/http-foundation@5aea19cd67 (2026-09-13). Data as JSON: /api/errors/97a2de2a44adf32f. Report an issue: GitHub.

Appendix: source

Thrown at Session/Storage/Handler/NativeFileSessionHandler.php:48

     *
     * @throws \InvalidArgumentException On invalid $savePath
     * @throws \RuntimeException         When failing to create the save directory
     */
    public function __construct(?string $savePath = null)
    {
        $baseDir = $savePath ??= \ini_get('session.save_path');

        if ($count = substr_count($savePath, ';')) {
            if ($count > 2) {
                throw new \InvalidArgumentException(\sprintf('Invalid argument $savePath \'%s\'.', $savePath));
            }

            // characters after last ';' are the path
            $baseDir = ltrim(strrchr($savePath, ';'), ';');
        }

        if ($baseDir && !is_dir($baseDir) && !@mkdir($baseDir, 0o777, true) && !is_dir($baseDir)) {
            throw new \RuntimeException(\sprintf('Session Storage was not able to create directory "%s".', $baseDir));
        }

        if ($savePath !== \ini_get('session.save_path')) {
            ini_set('session.save_path', $savePath);
        }
        if ('files' !== \ini_get('session.save_handler')) {
            ini_set('session.save_handler', 'files');
        }
    }

    public function clear(): void
    {
        $savePath = \ini_get('session.save_path');
        if (str_contains($savePath, ';')) {
            $savePath = ltrim(strrchr($savePath, ';'), ';');
        }

        $files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($savePath, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY);

View on GitHub (pinned to 5aea19cd67)