BookStackApp/BookStack · error · ThemeModuleException

Module in folder "{$folderName}" is missing a valid 'version

Error message

Module in folder "{$folderName}" is missing a valid 'version' property

What it means

ThemeModuleException guard in ThemeModule::fromJson rejecting a bookstack-module.json manifest whose 'version' value is absent or not a string. Input at fault: the module's JSON manifest with an invalid version field.

Source

Thrown at app/Theming/ThemeModule.php:31

    }

    /**
     * Create a ThemeModule instance from JSON data.
     *
     * @throws ThemeModuleException
     */
    public static function fromJson(array $data, string $folderName): self
    {
        if (empty($data['name']) || !is_string($data['name'])) {
            throw new ThemeModuleException("Module in folder \"{$folderName}\" is missing a valid 'name' property");
        }

        if (!isset($data['description']) || !is_string($data['description'])) {
            throw new ThemeModuleException("Module in folder \"{$folderName}\" is missing a valid 'description' property");
        }

        if (!isset($data['version']) || !is_string($data['version'])) {
            throw new ThemeModuleException("Module in folder \"{$folderName}\" is missing a valid 'version' property");
        }

        if (!preg_match('/^v?\d+\.\d+\.\d+(-.*)?$/', $data['version'])) {
            throw new ThemeModuleException("Module in folder \"{$folderName}\" has an invalid 'version' format. Expected semantic version format like '1.0.0' or 'v1.0.0'");
        }

        return new self(
            name: $data['name'],
            description: $data['description'],
            version: $data['version'],
            folderName: $folderName,
        );
    }

    /**
     * Get a path for a file within this module.
     */
    public function path($path = ''): string

View on GitHub (pinned to 18f8469a1c)

Solutions

  1. Add a 'version' key as a quoted string, e.g. "1.0.0"
  2. Quote numeric versions — unquoted JSON numbers fail the is_string check
  3. Follow semantic version format to also pass the next validation (see error 126)
  4. Bump the version string when republishing a fixed module

Example fix

// before
{ "version": 1.0 }
// after
{ "version": "1.0.0" }
Defensive patterns

Strategy: validation

Validate before calling

function validateVersionPresent(array $data, string $folder): void {
    if (!isset($data['version']) || !is_string($data['version'])) {
        throw new InvalidArgumentException("Module in folder \"{$folder}\" needs a string 'version'");
    }
}

Type guard

function hasStringVersion(array $data): bool {
    return isset($data['version']) && is_string($data['version']);
}

Try / catch

try {
    $module = ThemeModule::fromJson($data, $folderName);
} catch (ThemeModuleException $e) {
    if (str_contains($e->getMessage(), "'version' property")) {
        // instruct author to add a quoted semver string
    }
}

Prevention

When it happens

Trigger: fromJson receives $data where 'name' and 'description' are valid but 'version' is absent, null, or a non-string value (e.g. a float like 1.0 written without quotes, which PHP decodes as a number).

Common situations: Authors writing "version": 1.0 (unquoted number) in JSON; descriptors copied from templates without a version; hand-edited files where the version line was deleted.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of BookStackApp/BookStack@18f8469a1c (2026-09-02). Data as JSON: /api/errors/314e93cd54dba74e. Report an issue: GitHub.