symfony/http-kernel · error · RuntimeException

Unable to create the storage directory

Error message

Unable to create the storage directory (%s).

What it means

FileProfilerStorage throws this RuntimeException in its constructor when the storage folder taken from the DSN cannot be created. The constructor requires a DSN of the form 'file:/path/to/storage'; it attempts a recursive mkdir only if the directory does not already exist, then re-checks is_dir to handle races. If mkdir fails (permissions, read-only filesystem, path occupied by a file), this error is raised.

Solutions

  1. Verify the DSN starts with 'file:' and the path after it is absolute and correct (e.g. file:/var/cache/profiler).
  2. Create the directory manually and grant write access to the PHP/PHP-FPM user: mkdir -p /var/cache/profiler && chown www-data:www-data /var/cache/profiler.
  3. Check the path is not an existing file and the filesystem is writable (not a read-only mount, not full).
  4. Check open_basedir / SELinux / AppArmor restrictions that block mkdir at that path.
  5. If disk storage is not workable, switch the DSN to another profiler storage backend (e.g. redis:).

Example fix

// before
$storage = new FileProfilerStorage('file:/var/cache/profiler'); // dir missing, www-data cannot write /var/cache
// after
// $ mkdir -p /var/cache/profiler && chown www-data:www-data /var/cache/profiler
$storage = new FileProfilerStorage('file:/var/cache/profiler');
Defensive patterns

Strategy: validation

Validate before calling

$dsn = 'file:/var/cache/profiler';
if (!str_starts_with($dsn, 'file:')) {
    throw new \InvalidArgumentException('Profiler DSN must start with "file:"');
}
$dir = substr($dsn, 5);
if ($dir === '' || (!is_dir($dir) && !@mkdir($dir, 0777, true) && !is_dir($dir))) {
    throw new \RuntimeException("Cannot create profiler storage dir: {$dir}");
}

Type guard

function isUsableFileDsn(string $dsn): bool {
    if (!str_starts_with($dsn, 'file:')) return false;
    $dir = substr($dsn, 5);
    return $dir !== '' && (is_dir($dir) || is_writable(\dirname($dir)));
}

Try / catch

try {
    $storage = new FileProfilerStorage($dsn);
} catch (\RuntimeException $e) {
    error_log($e->getMessage());
    $storage = null; // disable profiling rather than failing the request
}

Prevention

When it happens

Trigger: Constructing FileProfilerStorage with a 'file:...' DSN whose target path cannot be created: parent directory not writable by the PHP user, disk full, path exists as a regular file, or open_basedir/SELinux blocking mkdir.

Common situations: Misconfigured profiler DSN in a Symfony app (framework.profiler storage DSN or PROFILE_DSN env), containers where var/cache is read-only or owned by another user, storage on an NFS/immutable volume, or a stale file occupying the directory path.

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-kernel@aa3a39d728 (2026-09-13). Data as JSON: /api/errors/9f6c8f7642b8ebcd. Report an issue: GitHub.

Appendix: source

Thrown at Profiler/FileProfilerStorage.php:41

     */
    private string $folder;

    /**
     * Constructs the file storage using a "dsn-like" path.
     *
     * Example : "file:/path/to/the/storage/folder"
     *
     * @throws \RuntimeException
     */
    public function __construct(string $dsn)
    {
        if (!str_starts_with($dsn, 'file:')) {
            throw new \RuntimeException(\sprintf('Please check your configuration. You are trying to use FileStorage with an invalid dsn "%s". The expected format is "file:/path/to/the/storage/folder".', $dsn));
        }
        $this->folder = substr($dsn, 5);

        if (!is_dir($this->folder) && !@mkdir($this->folder, 0o777, true) && !is_dir($this->folder)) {
            throw new \RuntimeException(\sprintf('Unable to create the storage directory (%s).', $this->folder));
        }
    }

    /**
     * @param-immediately-invoked-callable $filter
     */
    public function find(?string $ip, ?string $url, ?int $limit, ?string $method, ?int $start = null, ?int $end = null, ?string $statusCode = null, ?\Closure $filter = null): array
    {
        $file = $this->getIndexFilename();

        if (!file_exists($file)) {
            return [];
        }

        $file = fopen($file, 'r');
        fseek($file, 0, \SEEK_END);

        $result = [];

View on GitHub (pinned to aa3a39d728)