{"record":{"id":"b4248cbffcd2e735","repo":"HMCL-dev/HMCL","slug":"empty-old-version-number","errorCode":null,"errorMessage":"Empty old version number","messagePattern":"Empty old version number","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"HMCLCore/src/main/java/org/jackhuang/hmcl/util/versioning/GameVersionNumber.java","lineNumber":234,"sourceCode":"\n        if (gameVersion instanceof LegacySnapshot snapshot) {\n            String[] defaultVersions = Versions.DEFAULT_GAME_VERSIONS;\n            for (int i = defaultVersions.length - 1; i >= 0; i--) {\n                Release gaRelease = (Release) asGameVersion(defaultVersions[i]);\n\n                if (gaRelease.compareToSnapshot(snapshot) > 0) {\n                    return gaRelease;\n                }\n            }\n        }\n\n        return null;\n    }\n\n    public static final class Old extends GameVersionNumber {\n        static Old parse(String value) {\n            if (value.isEmpty())\n                throw new IllegalArgumentException(\"Empty old version number\");\n\n            Type type;\n            int prefixLength = 1;\n            switch (value.charAt(0)) {\n                case 'r':\n                    if (!value.startsWith(\"rd-\")) {\n                        throw new IllegalArgumentException(value);\n                    }\n\n                    type = Type.PRE_CLASSIC;\n                    prefixLength = \"rd-\".length();\n                    break;\n                case 'i':\n                    if (value.startsWith(\"inf-\")) {\n                        type = Type.INFDEV;\n                        prefixLength = \"inf-\".length();\n                    } else if (value.startsWith(\"in-\")) {\n                        type = Type.INDEV;","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCLCore/src/main/java/org/jackhuang/hmcl/util/versioning/GameVersionNumber.java#L216-L252","documentation":"GameVersionNumber.Old.parse throws IllegalArgumentException with the message 'Empty old version number' when asked to parse a legacy (pre-classic/alpha/beta) version identifier that is an empty string. The parser requires at least a type prefix character plus a digit, so empty input is rejected explicitly before the switch.","triggerScenarios":"Passing \"\" to GameVersionNumber parsing (e.g. via GameVersionNumber.asGameVersion or comparison helpers) when the version string came from an empty version field in a version.json, a missing manifest entry, or an unfilled config value.","commonSituations":"Custom version JSON with an empty id; profile/config data missing a version field; upstream version lists containing blank entries.","solutions":["Validate the version string is non-empty before calling the parser and substitute a sensible default (e.g. skip comparison or use Release.ZERO)","Fix the source data so the version id is populated","Wrap parsing in try-catch for IllegalArgumentException and treat empty as unknown version"],"exampleFix":"// before\nGameVersionNumber v = GameVersionNumber.asGameVersion(config.version);\n// after\nif (config.version == null || config.version.isEmpty()) {\n    return; // or use a default version\n}\nGameVersionNumber v = GameVersionNumber.asGameVersion(config.version);","handlingStrategy":"validation","validationCode":"static boolean isValidOldVersion(String v) {\n    return v != null && !v.isEmpty();\n}\n","typeGuard":null,"tryCatchPattern":"try {\n    GameVersionNumber v = GameVersionNumber.asGameVersion(raw);\n} catch (IllegalArgumentException e) {\n    log.warn(\"Invalid version '{}': {}\", raw, e.getMessage());\n}","preventionTips":["Never pass version fields straight from config/JSON without a null/empty check","Default missing version ids to a known placeholder or skip the comparison","Validate upstream data sources for blank version entries"],"tags":["java","version-parsing","empty-string"],"backgroundTag":"empty-required-field","analyzedSha":"24702dc5a0214034f4c27166d5fd30cad08cec19","analyzedAt":"2026-09-10T12:36:46.680Z","contentChangedAt":"2026-09-10T12:36:46.680Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}