{"record":{"id":"c227ae323a9288d1","repo":"octobercms/october","slug":"cms-lang-cms-object-invalid-file-extension","errorCode":null,"errorMessage":"cms::lang.cms_object.invalid_file_extension","messagePattern":"cms::lang\\.cms_object\\.invalid_file_extension","errorType":"validation","errorClass":"ValidationException","httpStatus":null,"severity":"warning","filePath":"modules/cms/classes/Lang.php","lineNumber":344,"sourceCode":"    protected function validateFileName($fileName = null)\n    {\n        if ($fileName === null) {\n            $fileName = $this->fileName;\n        }\n\n        $fileName = trim($fileName);\n\n        if (!strlen($fileName)) {\n            throw new ValidationException(['fileName' =>\n                LangHelper::get('cms::lang.cms_object.file_name_required', [\n                    'allowed' => implode(', ', $this->allowedExtensions),\n                    'invalid' => pathinfo($fileName, PATHINFO_EXTENSION)\n                ])\n            ]);\n        }\n\n        if (!FileHelper::validateExtension($fileName, $this->allowedExtensions, false)) {\n            throw new ValidationException(['fileName' =>\n                LangHelper::get('cms::lang.cms_object.invalid_file_extension', [\n                    'allowed' => implode(', ', $this->allowedExtensions),\n                    'invalid' => pathinfo($fileName, PATHINFO_EXTENSION)\n                ])\n            ]);\n        }\n\n        if (!FileHelper::validatePath($fileName, null)) {\n            throw new ValidationException(['fileName' =>\n                LangHelper::get('cms::lang.cms_object.invalid_file', [\n                    'name' => $fileName\n                ])\n            ]);\n        }\n    }\n\n    /**\n     * validate object","sourceCodeStart":326,"sourceCodeEnd":362,"githubUrl":"https://github.com/octobercms/october/blob/b608633a7e8922487d91a8161499020121c3b3bf/modules/cms/classes/Lang.php#L326-L362","documentation":"ValidationException thrown by `Lang::validateFileName()` when the file name's extension is not in `$allowedExtensions` — for theme lang files that list is exactly `['json']`. Theme translation files must be JSON; PHP-array or YAML translation formats from other systems are rejected here.","triggerScenarios":"Saving a lang object with fileName 'en.php' or 'messages.yaml'; importing translations in PHP array format from the application-level lang directory into a theme; scripts reusing file names from other CMS object types (pages use .htm).","commonSituations":"Migrating translations from Winter's `lang/` PHP files to theme lang files without converting; developers assuming all CMS objects share one extension; tooling that appends '.txt' to generated files.","solutions":["Use a .json file name (e.g. 'en.json') and JSON object content.","Convert PHP-array translations to JSON before importing (`json_encode(include $phpFile)`).","Validate the extension client-side with the allowed list from the API response."],"exampleFix":"// before — theme lang files are JSON only\n$lang->fill(['fileName' => 'en.php', 'content' => \"<?php return [];\"]);\n\n// after\n$lang->fill(['fileName' => 'en.json', 'content' => '{\"hello.world\": \"Hello\"}']);","handlingStrategy":"validation","validationCode":"$ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));\nif ($ext !== 'json') {\n    throw new ValidationException(['fileName' => 'Theme lang files must use the .json extension.']);\n}\n$lang->fileName = $fileName;\n$lang->save();","typeGuard":null,"tryCatchPattern":"try {\n    $lang->save();\n} catch (Winter\\Storm\\Exception\\ValidationException $e) {\n    return back()->withErrors($e->getErrors())->withInput();\n}","preventionTips":["Convert PHP-array translations to JSON (json_encode) before importing into themes.","Validate the extension in your UI's accept attribute and server-side rules.","Remember each CMS object type has its own extension: pages/partials/layouts .htm, lang .json."],"tags":["validation","file-extension","lang","import"],"backgroundTag":"invalid-file-extension","analyzedSha":"b608633a7e8922487d91a8161499020121c3b3bf","analyzedAt":"2026-08-21T04:24:57.515Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}