{"record":{"id":"7794a5051e3ec54a","repo":"HMCL-dev/HMCL","slug":"manifest-is-null-7794a5","errorCode":null,"errorMessage":"Manifest is null","messagePattern":"Manifest is null","errorType":"validation","errorClass":"JsonParseException","httpStatus":null,"severity":"error","filePath":"HMCLCore/src/main/java/org/jackhuang/hmcl/game/DefaultGameRepository.java","lineNumber":367,"sourceCode":"        try {\n            manifest = readInstanceManifest(json);\n        } catch (Exception e) {\n            LOG.warning(\"Malformed instance json \" + id + \" (\" + json + \")\", e);\n            return null;\n        }\n\n        // Directory name is the repository identity; keep the on-disk files untouched.\n        if (!id.equals(manifest.id())) {\n            manifest = manifest.withId(id);\n        }\n\n        return createInstance(snapshot, id, manifest, manifestFileOverride);\n    }\n\n    private static GameInstanceManifest readInstanceManifest(Path json) throws IOException, JsonParseException {\n        GameInstanceManifest manifest = JsonUtils.fromJsonFile(json, GameInstanceManifest.class);\n        if (manifest == null) {\n            throw new JsonParseException(\"Manifest is null\");\n        }\n        return manifest;\n    }\n\n    static void moveInstanceFiles(Path baseDirectory, GameInstanceID from, GameInstanceID to) throws IOException {\n        Path instancesDir = baseDirectory.resolve(\"versions\");\n        Path fromDir = instancesDir.resolve(from.id());\n        Path toDir = instancesDir.resolve(to.id());\n        Files.move(fromDir, toDir);\n\n        Path fromJson = toDir.resolve(from + \".json\");\n        Path fromJar = toDir.resolve(from + \".jar\");\n        Path toJson = toDir.resolve(to + \".json\");\n        Path toJar = toDir.resolve(to + \".jar\");\n\n        boolean hasJarFile = Files.exists(fromJar);\n\n        try {","sourceCodeStart":349,"sourceCodeEnd":385,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCLCore/src/main/java/org/jackhuang/hmcl/game/DefaultGameRepository.java#L349-L385","documentation":"readInstanceManifest() loads an instance manifest JSON from disk into GameInstanceManifest; JsonUtils.fromJsonFile may legitimately return null (e.g. file parsed as an empty document), which would silently produce a broken instance. HMCL deliberately throws JsonParseException('Manifest is null') so a null manifest aborts instance loading instead of being passed downstream. Called from loadInstanceDirectory when scanning the instances directory.","triggerScenarios":"Calling loadInstanceDirectory / opening a repository on a manifest json that parses to null — typically an empty file (0 bytes) or a file containing only 'null' — inside versions/<id>/instance.json-style manifests.","commonSituations":"Interrupted instance creation or migration leaving an empty manifest file; a crash during write; users copying instance folders but truncating files; sync tools uploading empty placeholders.","solutions":["Delete or restore the empty/null manifest file and let the repository re-import or recreate the instance","Re-download or re-copy the complete instance directory including a valid manifest json","Wrap instance loading in try-catch for JsonParseException and skip/report that instance instead of failing the whole repository scan","Check for 0-byte files under the instance directory before loading"],"exampleFix":"// before\nGameInstanceManifest m = repo.loadInstance(dir); // throws on empty manifest\n// after\ntry {\n    GameInstanceManifest m = repo.loadInstance(dir);\n} catch (JsonParseException e) {\n    LOG.warning(\"Skipping broken instance at \" + dir + \": \" + e.getMessage());\n}","handlingStrategy":"try-catch","validationCode":"Path manifest = dir.resolve(\"instance.json\");\nboolean valid = Files.isRegularFile(manifest) && Files.size(manifest) > 2;\nif (!valid) restoreOrRecreateManifest(dir);","typeGuard":null,"tryCatchPattern":"try {\n    GameInstanceManifest m = repo.loadInstanceDirectory(dir);\n} catch (JsonParseException e) {\n    LOG.warning(\"Skipping instance with null/corrupt manifest: \" + dir);\n}","preventionTips":["Write manifests atomically (temp file + atomic move)","Check for empty files after sync/copy operations","Back up instance metadata before migrating instances"],"tags":["json","null-check","minecraft-instance-metadata"],"backgroundTag":"json-unmarshal-failed","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"}