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
- Create the log directory and grant write permission to the PHP process user (chown/chmod var/log)
- Verify the output path/stream wrapper is correct
- Run the app as a user with write access to the target
- 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
- Ensure log directories exist and are writable by the PHP user before boot
- Use a fallback stream (php://stderr) in containers
- Check volume mounts and SELinux policies in deployment
- Pre-create log dirs in Dockerfile/entrypoint
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
- Failed to write cache file
- Unable to create the store directory
- The log level " " does not exist.
- Invalid log level " ".
- Unable to create the storage directory
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)