{"record":{"id":"904a092790b1dcbc","repo":"BookStackApp/BookStack","slug":"module-in-folder-foldername-is-missing-a-vali-904a09","errorCode":null,"errorMessage":"Module in folder \"{$folderName}\" is missing a valid 'description' property","messagePattern":"Module in folder \"(.+?)\" is missing a valid 'description' property","errorType":"exception","errorClass":"ThemeModuleException","httpStatus":null,"severity":"error","filePath":"app/Theming/ThemeModule.php","lineNumber":27,"sourceCode":"        public string $description,\n        public string $version,\n        public string $folderName,\n    ) {\n    }\n\n    /**\n     * Create a ThemeModule instance from JSON data.\n     *\n     * @throws ThemeModuleException\n     */\n    public static function fromJson(array $data, string $folderName): self\n    {\n        if (empty($data['name']) || !is_string($data['name'])) {\n            throw new ThemeModuleException(\"Module in folder \\\"{$folderName}\\\" is missing a valid 'name' property\");\n        }\n\n        if (!isset($data['description']) || !is_string($data['description'])) {\n            throw new ThemeModuleException(\"Module in folder \\\"{$folderName}\\\" is missing a valid 'description' property\");\n        }\n\n        if (!isset($data['version']) || !is_string($data['version'])) {\n            throw new ThemeModuleException(\"Module in folder \\\"{$folderName}\\\" is missing a valid 'version' property\");\n        }\n\n        if (!preg_match('/^v?\\d+\\.\\d+\\.\\d+(-.*)?$/', $data['version'])) {\n            throw new ThemeModuleException(\"Module in folder \\\"{$folderName}\\\" has an invalid 'version' format. Expected semantic version format like '1.0.0' or 'v1.0.0'\");\n        }\n\n        return new self(\n            name: $data['name'],\n            description: $data['description'],\n            version: $data['version'],\n            folderName: $folderName,\n        );\n    }\n","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/BookStackApp/BookStack/blob/18f8469a1c72f8cc8497e9372635e6dea5028071/app/Theming/ThemeModule.php#L9-L45","documentation":"ThemeModuleException guard in ThemeModule::fromJson rejecting a bookstack-module.json manifest whose 'description' value is absent or not a string. Input at fault: the module's JSON manifest with an invalid description field.","triggerScenarios":"fromJson (invoked by loadFromFolder/getModuleInstance) receives $data with 'name' valid but 'description' missing, null, or a non-string (e.g. a number or array).","commonSituations":"Minimal module descriptors that only include a name; templates from old BookStack versions before description became required; copy-pasted descriptors with the key removed or renamed.","solutions":["Add a string 'description' field to the module descriptor in the folder named in the message","Ensure the value is a plain string, not a nested object/array or number","Update the module to a version compatible with your BookStack release","Validate the descriptor JSON parses correctly (syntax errors can drop keys)"],"exampleFix":"// before\n{ \"name\": \"my-module\" }\n// after\n{ \"name\": \"my-module\", \"description\": \"Adds a custom footer to pages\" }","handlingStrategy":"validation","validationCode":"function validateDescription(array $data, string $folder): void {\n    if (!isset($data['description']) || !is_string($data['description'])) {\n        throw new InvalidArgumentException(\"Module in folder \\\"{$folder}\\\" needs a string 'description'\");\n    }\n}","typeGuard":"function hasValidDescription(array $data): bool {\n    return isset($data['description']) && is_string($data['description']);\n}","tryCatchPattern":"try {\n    $module = ThemeModule::fromJson($data, $folderName);\n} catch (ThemeModuleException $e) {\n    if (str_contains($e->getMessage(), \"'description'\")) {\n        // show author which property to add\n    }\n}","preventionTips":["Always add a human-readable 'description' string to module descriptors","Start from the official module template/starter","Run a schema check (name, description, version as strings) in CI before packaging","Avoid programmatic generation that can emit null for optional-looking fields"],"tags":["theming","validation","json","bookstack"],"backgroundTag":"missing-required-argument","analyzedSha":"18f8469a1c72f8cc8497e9372635e6dea5028071","analyzedAt":"2026-09-02T19:49:33.068Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}