symfony/http-kernel · error · InvalidArgumentException

Unable to open " ".

Error message

Unable to open "%s".

What it means

The Log\Logger constructor opens the configured output target (a file path or URL) with fopen(..., 'a'); if that fails it throws InvalidArgumentException with this message. It means the logger cannot write to the destination provided.

Solutions

  1. Create the log directory and grant write permission to the PHP process user (chown/chmod var/log)
  2. Verify the output path/stream wrapper is correct
  3. Run the app as a user with write access to the target
  4. Check SELinux/container volume mount permissions

Example fix

// before
new Logger(LogLevel::ERROR, '/var/log/app/app.log'); // dir missing

// after
if (!is_dir('/var/log/app')) { mkdir('/var/log/app', 0775, true); }
new Logger(LogLevel::ERROR, '/var/log/app/app.log');
Defensive patterns

Strategy: validation

Validate before calling

$dir = dirname($output);
if (!is_dir($dir) && !@mkdir($dir, 0775, true)) { throw new \RuntimeException("Cannot create log dir: $dir"); }
if (!is_writable($dir)) { throw new \RuntimeException("Log dir not writable: $dir"); }

Try / catch

try { $logger = new \Symfony\Component\HttpKernel\Log\Logger($minLevel, $output); } catch (\InvalidArgumentException $e) { error_log('Logger output unavailable: '.$e->getMessage()); $logger = new \Symfony\Component\HttpKernel\Log\Logger($minLevel, 'php://stderr'); }

Prevention

When it happens

Trigger: Passing a $output string path that cannot be opened in append mode: nonexistent directory, missing write permission, invalid wrapper/URL, or a non-resource/non-null $output value that is falsy-mapped to false.

Common situations: Log directory doesn't exist or isn't writable by the PHP user; var/log not writable in containers; wrong stream wrapper (e.g. 'file://typo'); SELinux/AppArmor blocking writes; disk permissions after deployment.

Understand the failure class

Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.

Related errors


AI-assisted analysis of symfony/http-kernel@aa3a39d728 (2026-09-13). Data as JSON: /api/errors/f6cc86cab4e8834c. Report an issue: GitHub.

Appendix: source

Thrown at Log/Logger.php:77

     */
    public function __construct(?string $minLevel = null, $output = null, ?callable $formatter = null, private readonly ?RequestStack $requestStack = null, bool $debug = false)
    {
        $minLevel ??= match ((int) ($_ENV['SHELL_VERBOSITY'] ?? $_SERVER['SHELL_VERBOSITY'] ?? 0)) {
            -1 => LogLevel::ERROR,
            1 => LogLevel::NOTICE,
            2 => LogLevel::INFO,
            3 => LogLevel::DEBUG,
            default => null === $output || 'php://stdout' === $output || 'php://stderr' === $output ? LogLevel::ERROR : LogLevel::WARNING,
        };

        if (!isset(self::LEVELS[$minLevel])) {
            throw new InvalidArgumentException(\sprintf('The log level "%s" does not exist.', $minLevel));
        }

        $this->minLevelIndex = self::LEVELS[$minLevel];
        $this->formatter = null !== $formatter ? $formatter(...) : $this->format(...);
        if ($output && false === $this->handle = \is_string($output) ? @fopen($output, 'a') : $output) {
            throw new InvalidArgumentException(\sprintf('Unable to open "%s".', $output));
        }
        $this->debug = $debug;
    }

    public function enableDebug(): void
    {
        $this->debug = true;
    }

    public function log($level, $message, array $context = []): void
    {
        if (!isset(self::LEVELS[$level])) {
            throw new InvalidArgumentException(\sprintf('The log level "%s" does not exist.', $level));
        }

        if (self::LEVELS[$level] < $this->minLevelIndex) {
            return;
        }

View on GitHub (pinned to aa3a39d728)