{"record":{"id":"fe6a072f3714f2eb","repo":"octobercms/october","slug":"cms-lang-cms-object-error-creating-directory","errorCode":null,"errorMessage":"cms::lang.cms_object.error_creating_directory","messagePattern":"cms::lang\\.cms_object\\.error_creating_directory","errorType":"exception","errorClass":"ApplicationException","httpStatus":null,"severity":"error","filePath":"modules/cms/classes/Lang.php","lineNumber":266,"sourceCode":"     * save the object to the disk\n     */\n    public function save(array $options = [])\n    {\n        $this->validateFileName();\n\n        $fullPath = $this->getFilePath();\n\n        if (File::isFile($fullPath) && $this->originalFileName !== $this->fileName) {\n            throw new ApplicationException(LangHelper::get(\n                'cms::lang.cms_object.file_already_exists',\n                ['name'=>$this->fileName]\n            ));\n        }\n\n        $dirPath = $this->theme->getPath().'/'.$this->dirName;\n        if (!file_exists($dirPath) || !is_dir($dirPath)) {\n            if (!File::makeDirectory($dirPath, 0755, true, true)) {\n                throw new ApplicationException(LangHelper::get(\n                    'cms::lang.cms_object.error_creating_directory',\n                    ['name'=>$dirPath]\n                ));\n            }\n        }\n\n        $newFullPath = $fullPath;\n        if (@File::put($fullPath, $this->content) === false) {\n            throw new ApplicationException(LangHelper::get(\n                'cms::lang.cms_object.error_saving',\n                ['name'=>$this->fileName]\n            ));\n        }\n\n        if (strlen($this->originalFileName) && $this->originalFileName !== $this->fileName) {\n            $fullPath = $this->getFilePath($this->originalFileName);\n\n            if (File::isFile($fullPath)) {","sourceCodeStart":248,"sourceCodeEnd":284,"githubUrl":"https://github.com/octobercms/october/blob/b608633a7e8922487d91a8161499020121c3b3bf/modules/cms/classes/Lang.php#L248-L284","documentation":"ApplicationException thrown by `Lang::save()` when `File::makeDirectory()` fails to create the theme's `lang/` directory. This happens on the first lang-file save in a theme that has no lang/ folder yet, and almost always means the web server user lacks write permission on the theme directory (or the path is blocked by open_basedir / a read-only mount).","triggerScenarios":"First save of a theme lang file on a server where `themes/<theme>/` is owned by root or lacks write permission for PHP; deploying themes via git as root so the directory is not writable by the www-data user; open_basedir restrictions excluding the theme path.","commonSituations":"Production servers with read-only theme deploys; permissions lost after server migration or restore; containerized deployments with wrong volume ownership; SELinux denying directory creation.","solutions":["Give the web server user write access: `chown -R www-data:www-data themes/<theme>` (or group-write with the right group).","Verify the path is inside allowed open_basedir limits and the filesystem is not mounted read-only.","Pre-create `themes/<theme>/lang/` in your deployment with correct ownership so makeDirectory is never needed at runtime."],"exampleFix":"# before — theme dir not writable by PHP\n$ ls -ld themes/mytheme\ndrwxr-xr-x root root themes/mytheme\n\n# after — grant web server user ownership\nsudo chown -R www-data:www-data themes/mytheme\nsudo chmod -R u+rwX themes/mytheme","handlingStrategy":"validation","validationCode":"$dir = $theme->getPath() . '/' . $lang->dirName;\nif (!is_dir($dir) && !is_writable($theme->getPath())) {\n    return back()->with('error', 'Theme directory is not writable — fix permissions first.');\n}\n$lang->save();","typeGuard":null,"tryCatchPattern":"try {\n    $lang->save();\n} catch (ApplicationException $e) {\n    // error_creating_directory / error_saving: surface an ops-friendly message\n    report($e);\n    return response()->json(['error' => 'Server cannot write to the theme directory. Contact the administrator.'], 500);\n}","preventionTips":["Pre-create themes/<theme>/lang/ in your deployment pipeline with correct ownership.","Ship an install/health check that asserts is_writable(themes_path()) and fails loudly at deploy time.","Keep web-server ownership (www-data) on the whole themes/ tree in writable deployments."],"tags":["filesystem","permissions","io","lang","deployment"],"backgroundTag":"filesystem-permission-denied","analyzedSha":"b608633a7e8922487d91a8161499020121c3b3bf","analyzedAt":"2026-08-21T04:24:57.515Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}