{"record":{"id":"8f78d2ad0cbfdd79","repo":"halo-dev/halo","slug":"illegal-requires-version-expression","errorCode":null,"errorMessage":"Illegal requires version expression.","messagePattern":"Illegal requires version expression\\.","errorType":"http","errorClass":"ServerWebInputException","httpStatus":400,"severity":"warning","filePath":"application/src/main/java/run/halo/app/infra/utils/VersionUtils.java","lineNumber":46,"sourceCode":"\n    /**\n     * Checks if a version satisfies the specified SemVer {@link Expression} string. If the constraint is empty or null\n     * then the method returns true. Constraint examples: {@code >2.0.0} (simple), {@code \">=1.4.0 & <1.6.0\"} (range).\n     * See <a\n     * href=\"https://github.com/zafarkhaja/jsemver#semver-expressions-api-ranges\">semver-expressions-api-ranges</a> for\n     * more info.\n     *\n     * @param version the version to check\n     * @param constraint the SemVer Expression string\n     * @return true if version satisfies the constraint or if constraint was left blank\n     */\n    public static boolean checkVersionConstraint(String version, String constraint) {\n        try {\n            return StringUtils.isBlank(constraint)\n                    || \"*\".equals(constraint)\n                    || Version.parse(version).satisfies(constraint);\n        } catch (Exception e) {\n            throw new ServerWebInputException(\"Illegal requires version expression.\", null, e);\n        }\n    }\n}\n","sourceCodeStart":28,"sourceCodeEnd":50,"githubUrl":"https://github.com/halo-dev/halo/blob/d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8/application/src/main/java/run/halo/app/infra/utils/VersionUtils.java#L28-L50","documentation":"Thrown as ServerWebInputException (HTTP 400) by VersionUtils.checkVersionConstraint when parsing/evaluating a SemVer constraint expression throws any exception. It wraps failures from com.github.zafarkhaja.semver (invalid version or malformed expression) into a client-facing bad-input error. Blank or '*' constraints are allowed and never reach the parser.","triggerScenarios":"A plugin 'requires' / version-constraint string that is non-blank, not '*', and either is an unparseable version or a malformed SemVer expression (e.g. '>>2.0.0', 'foo', '1.x&<2').","commonSituations":"A plugin manifest with a typo in requires; an unsupported operator; copy-pasting npm-style ranges into a SemVer field; version strings with build metadata in an invalid position.","solutions":["Fix the constraint expression to valid SemVer syntax (e.g. '>=1.4.0 & <2.0.0', '~1.2', '^1.2.3').","Leave the constraint blank or set it to '*' if any version is acceptable.","Validate the expression with a SemVer parser locally before deploying the plugin.","Confirm the version being matched is a clean x.y.z SemVer string."],"exampleFix":"// before\nrequires: \">>2.0.0\"\n\n// after\nrequires: \">=2.0.0\"","handlingStrategy":"validation","validationCode":"if (StringUtils.isNotBlank(constraint) && !\"*\".equals(constraint)) {\n    try {\n        Version.parse(version).satisfies(constraint);\n    } catch (Exception parseEx) {\n        throw new IllegalArgumentException(\"Invalid SemVer constraint: \" + constraint, parseEx);\n    }\n}","typeGuard":"static boolean isValidSemverConstraint(String c) {\n    if (StringUtils.isBlank(c) || \"*\".equals(c)) return true;\n    try { Version.valueOf(\"1.0.0\").satisfies(c); return true; } catch (Exception e) { return false; }\n}","tryCatchPattern":"try {\n    boolean ok = VersionUtils.checkVersionConstraint(version, requires);\n} catch (ServerWebInputException e) {\n    // HTTP 400 already; surface to plugin author with the parse error\n    return ServerResponse.badRequest().bodyValue(\"Invalid 'requires' expression: \" + e.getCause().getMessage());\n}","preventionTips":["Lint plugin 'requires' with a SemVer parser during plugin build.","Keep constraints to well-known operators (>=, <, ~, ^, ranges with &).","Test the constraint against the target Halo version before release."],"tags":["versioning","semver","plugin","validation","bad-request"],"backgroundTag":null,"analyzedSha":"d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8","analyzedAt":"2026-08-14T00:18:38.915Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}