{"record":{"id":"b0883373dbd0a4fa","repo":"BookStackApp/BookStack","slug":"module-in-folder-foldername-has-an-invalid-v","errorCode":null,"errorMessage":"Module in folder \"{$folderName}\" has an invalid 'version' format. Expected semantic version format like '1.0.0' or 'v1.0.0'","messagePattern":"Module in folder \"(.+?)\" has an invalid 'version' format\\. Expected semantic version format like '1\\.0\\.0' or 'v1\\.0\\.0'","errorType":"exception","errorClass":"ThemeModuleException","httpStatus":null,"severity":"error","filePath":"app/Theming/ThemeModule.php","lineNumber":35,"sourceCode":"     *\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\n    /**\n     * Get a path for a file within this module.\n     */\n    public function path($path = ''): string\n    {\n        $component = trim($path, '/');\n        return theme_path(\"modules/{$this->folderName}/{$component}\");\n    }","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/BookStackApp/BookStack/blob/18f8469a1c72f8cc8497e9372635e6dea5028071/app/Theming/ThemeModule.php#L17-L53","documentation":"ThemeModule::fromJson throws ThemeModuleException when 'version' is a string but does not match the semantic-version regex /^v?\\d+\\.\\d+\\.\\d+(-.*)?$/ — it must look like '1.0.0' or 'v1.0.0', optionally with a pre-release suffix.","triggerScenarios":"Descriptor has a string 'version' such as '1.0', 'v1', '1.0.0.1', 'beta', or '1.0.0 beta' (space instead of hyphen) that fails the semver pattern.","commonSituations":"Two-part versions ('1.0'); informal tags ('latest', 'dev'); versions with spaces or build metadata in the wrong place; authors used to loose versioning from other platforms.","solutions":["Rewrite the version as MAJOR.MINOR.PATCH, e.g. '1.0.0'","Optionally prefix with 'v' ('v1.0.0' is accepted)","Put pre-release info after a hyphen, e.g. '1.0.0-beta.1'","Remove extra components like a fourth number or trailing metadata that breaks the pattern"],"exampleFix":"// before\n\"version\": \"1.0 beta\"\n// after\n\"version\": \"1.0.0-beta\"","handlingStrategy":"validation","validationCode":"function validateSemver(string $version): bool {\n    return preg_match('/^v?\\d+\\.\\d+\\.\\d+(-.*)?$/', $version) === 1;\n}\n// run before packaging: if (!validateSemver($data['version'])) fail;","typeGuard":"function isSemverString(mixed $v): bool {\n    return is_string($v) && preg_match('/^v?\\d+\\.\\d+\\.\\d+(-.*)?$/', $v) === 1;\n}","tryCatchPattern":"try {\n    $module = ThemeModule::fromJson($data, $folderName);\n} catch (ThemeModuleException $e) {\n    if (str_contains($e->getMessage(), \"invalid 'version' format\")) {\n        // prompt for MAJOR.MINOR.PATCH format\n    }\n}","preventionTips":["Adopt strict semver (three numeric parts, optional leading 'v')","Put pre-release tags after a hyphen: '1.0.0-beta.1'","Validate versions with the same regex in release tooling","Avoid informal tags like 'latest', 'dev', or two-part versions"],"tags":["theming","validation","semver","json","bookstack"],"backgroundTag":"invalid-version-format","analyzedSha":"18f8469a1c72f8cc8497e9372635e6dea5028071","analyzedAt":"2026-09-02T19:49:33.068Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}