{"record":{"id":"e316b5f5136cb435","repo":"symfony/translation","slug":"unable-to-create-directory-s","errorCode":null,"errorMessage":"Unable to create directory \"%s\".","messagePattern":"Unable to create directory \"(.+?)\"\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"Dumper/FileDumper.php","lineNumber":53,"sourceCode":"     */\n    public function setRelativePathTemplate(string $relativePathTemplate): void\n    {\n        $this->relativePathTemplate = $relativePathTemplate;\n    }\n\n    public function dump(MessageCatalogue $messages, array $options = []): void\n    {\n        if (!\\array_key_exists('path', $options)) {\n            throw new InvalidArgumentException('The file dumper needs a path option.');\n        }\n\n        // save a file for each domain\n        foreach ($messages->getDomains() as $domain) {\n            $fullpath = $options['path'].'/'.$this->getRelativePath($domain, $messages->getLocale());\n            if (!file_exists($fullpath)) {\n                $directory = \\dirname($fullpath);\n                if (!file_exists($directory) && !@mkdir($directory, 0o777, true)) {\n                    throw new RuntimeException(\\sprintf('Unable to create directory \"%s\".', $directory));\n                }\n            }\n\n            $intlDomain = $domain.MessageCatalogue::INTL_DOMAIN_SUFFIX;\n            $intlMessages = $messages->all($intlDomain);\n\n            if ($intlMessages) {\n                $intlPath = $options['path'].'/'.$this->getRelativePath($intlDomain, $messages->getLocale());\n                file_put_contents($intlPath, $this->formatCatalogue($messages, $intlDomain, $options));\n\n                $messages->replace([], $intlDomain);\n\n                try {\n                    if ($messages->all($domain)) {\n                        file_put_contents($fullpath, $this->formatCatalogue($messages, $domain, $options));\n                    }\n                    continue;\n                } finally {","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/symfony/translation/blob/ae9e8a51bc29780d63c7f9efd6005d7c875e100b/Dumper/FileDumper.php#L35-L71","documentation":"Thrown by FileDumper::dump when mkdir() fails to create the target directory (or its parents) for the translation output file. The call is silenced with @, so any failure (permissions, path exists as file, read-only FS) surfaces as this RuntimeException.","triggerScenarios":"dump() computes $fullpath = options['path'] + relative path; the parent directory does not exist and `mkdir($dir, 0777, true)` returns false — e.g. parent dir not writable, path segment is an existing file, or open_basedir restrictions.","commonSituations":"Writing translations to a directory owned by another user in production; Docker containers running as non-root with read-only volumes; a file existing where a directory is expected; misconfigured path parameter.","solutions":["Check/fix filesystem permissions on the parent directory so the PHP process can create it","Verify no file exists at the directory path; remove or rename it","Ensure the 'path' option points to a writable, correct location","If using containers, mount the translations directory as writable by the runtime user"],"exampleFix":"// before\n$dumper->dump($catalogue, ['path' => '/var/www/app/translations']); // /var/www/app not writable\n// after\n$dumper->dump($catalogue, ['path' => $kernel->getCacheDir().'/translations']);","handlingStrategy":"try-catch","validationCode":"$dir = $options['path']; if (!is_dir($dir) && !@mkdir($dir, 0777, true) && !is_dir($dir)) { throw new \\RuntimeException(\"Cannot prepare output dir {$dir}: \".error_get_last()['message']); }","typeGuard":"function isWritableOutputDir(string $path): bool { return is_dir($path) && is_writable($path); }","tryCatchPattern":"try { $dumper->dump($catalogue, $options); } catch (RuntimeException $e) { if (str_starts_with($e->getMessage(), 'Unable to create directory')) { // check permissions / run as correct user } throw $e; }","preventionTips":["Pre-create output directories in deployment scripts with correct ownership","Ensure the PHP process user owns or has write access to the translations dir","In Docker, declare the output path as a writable VOLUME and avoid read-only rootfs for it"],"tags":["symfony","translation","dumper","filesystem","mkdir"],"backgroundTag":"mkdir-permission-denied","analyzedSha":"ae9e8a51bc29780d63c7f9efd6005d7c875e100b","analyzedAt":"2026-09-15T22:29:15.305Z","contentChangedAt":"2026-09-15T22:29:15.305Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}