{"record":{"id":"00abd210138b5420","repo":"HMCL-dev/HMCL","slug":"forgeversion-version-cannot-be-null","errorCode":null,"errorMessage":"ForgeVersion version cannot be null","messagePattern":"ForgeVersion version cannot be null","errorType":"validation","errorClass":"JsonParseException","httpStatus":null,"severity":"error","filePath":"HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeBMCLVersionList.java","lineNumber":195,"sourceCode":"            return modified;\n        }\n\n        @NotNull\n        public String getVersion() {\n            return version;\n        }\n\n        @NotNull\n        public List<File> getFiles() {\n            return files;\n        }\n\n        @Override\n        public void validate() throws JsonParseException {\n            if (files == null)\n                throw new JsonParseException(\"ForgeVersion files cannot be null\");\n            if (version == null)\n                throw new JsonParseException(\"ForgeVersion version cannot be null\");\n            if (mcversion == null)\n                throw new JsonParseException(\"ForgeVersion mcversion cannot be null\");\n        }\n\n        @Immutable\n        public static final class File {\n            private final String format;\n            private final String category;\n            private final String hash;\n\n            public File() {\n                this(\"\", \"\", \"\");\n            }\n\n            public File(String format, String category, String hash) {\n                this.format = format;\n                this.category = category;\n                this.hash = hash;","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeBMCLVersionList.java#L177-L213","documentation":"This is a generic validation guard in ForgeVersion.validate(): after JSON deserialization, the version field is null, meaning the remote Forge metadata entry is missing its required version identifier. As a sentinel check it fires on any incomplete server response rather than a specific malformed value.","triggerScenarios":"Parsing a Forge version list JSON entry that lacks a 'version' string and then calling validate().","commonSituations":"Mirror API returning partial entries, manual edits to cached version JSON, or mapping changes between BMCLAPI and the local model.","solutions":["Supply the missing 'version' field in the JSON entry","Catch JsonParseException and filter out malformed entries","Refresh the version list from a reliable mirror"],"exampleFix":"// before\n{\"files\": [...]} // version omitted\nversion.validate();\n// after\n{\"version\": \"47.1.3\", \"mcversion\": \"1.20.1\", \"files\": [...]}\nversion.validate();","handlingStrategy":"validation","validationCode":"if (versionObject.get(\"version\") == null || versionObject.get(\"version\").isJsonNull())\n    throw new JsonParseException(\"ForgeVersion version missing\");","typeGuard":"static boolean hasVersion(JsonObject entry) {\n    return entry.get(\"version\") instanceof JsonPrimitive p && p.isString() && !p.getAsString().isBlank();\n}","tryCatchPattern":"try {\n    forgeVersion.validate();\n} catch (JsonParseException e) {\n    LOG.warning(\"Skipping entry with missing version: \" + e.getMessage());\n}","preventionTips":["Schema-check downloaded version lists with a JSON schema","Filter null-version entries right after parsing","Prefer official promotions JSON when the mirror returns partial data"],"tags":["java","forge","json","mirror"],"backgroundTag":"schema-validation-failed","analyzedSha":"24702dc5a0214034f4c27166d5fd30cad08cec19","analyzedAt":"2026-09-10T12:36:46.680Z","contentChangedAt":"2026-09-10T12:36:46.680Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}