{"record":{"id":"cae17e4349fc41e9","repo":"HMCL-dev/HMCL","slug":"asset-index-file-malformed","errorCode":null,"errorMessage":"Asset index file malformed","messagePattern":"Asset index file malformed","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"HMCLCore/src/main/java/org/jackhuang/hmcl/game/DefaultGameInstance.java","lineNumber":302,"sourceCode":"            return manifestFile.resolveSibling(FileUtils.getNameWithoutExtension(manifestFile) + \".jar\");\n        }\n        return layout.getInstanceJarFile(id);\n    }\n\n    @Override\n    public Path getRunDirectory() {\n        // Official layout: shared working directory is the repository base directory.\n        return getRepository().getBaseDirectory();\n    }\n\n    /// {@inheritDoc}\n    @Override\n    public AssetIndex getAssetIndex(String assetId) throws IOException {\n        try {\n            return Objects.requireNonNull(\n                    JsonUtils.fromJsonFile(getLayout().getAssetIndexFile(assetId), AssetIndex.class));\n        } catch (JsonParseException | NullPointerException e) {\n            throw new IOException(\"Asset index file malformed\", e);\n        }\n    }\n\n    /// {@inheritDoc}\n    @Override\n    public Path getActualAssetDirectory(String assetId) {\n        try {\n            return reconstructAssets(assetId);\n        } catch (IOException | JsonParseException e) {\n            LOG.error(\"Unable to reconstruct asset directory\", e);\n            return getLayout().getAssetDirectory();\n        }\n    }\n\n    /// {@inheritDoc}\n    @Override\n    public Optional<Path> getAssetObject(String assetId, String name) throws IOException {\n        try {","sourceCodeStart":284,"sourceCodeEnd":320,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCLCore/src/main/java/org/jackhuang/hmcl/game/DefaultGameInstance.java#L284-L320","documentation":"DefaultGameInstance.getAssetIndex() parses versions/<id>/assets/<assetId>.json (or the indexed asset index) into an AssetIndex. If the file is missing (NPE from Objects.requireNonNull after fromJsonFile returns null) or is not valid/parseable JSON (JsonParseException), it is wrapped in an IOException with message 'Asset index file malformed'. This means the Minecraft asset index metadata is absent or corrupted, not that assets themselves are missing.","triggerScenarios":"Calling getAssetIndex(assetId) when the asset index file does not exist on disk, was truncated by an interrupted download, or contains invalid JSON; getAssetObject() propagates this through assetObject().","commonSituations":"Interrupted game downloads leaving a zero-byte or partial asset index json; manual deletion during cleanup; disk corruption; pointing a custom instance at an assetId whose index was never downloaded.","solutions":["Delete the corrupt assets/indexes/<assetId>.json and re-download it (relaunch the game or trigger the asset repair in HMCL)","Verify the file exists before calling getAssetIndex and download it from Mojang's asset index URL if missing","Catch this IOException and fall back to re-verifying/re-downloading game assets rather than failing the launch","Check disk space and permissions if re-downloads keep producing truncated files"],"exampleFix":"// before\nAssetIndex index = instance.getAssetIndex(\"17\");\n// after\nPath indexFile = instance.getLayout().getAssetIndexFile(\"17\");\nif (!Files.isRegularFile(indexFile) || Files.size(indexFile) == 0) {\n    downloadAssetIndex(\"17\");\n}\nAssetIndex index = instance.getAssetIndex(\"17\");","handlingStrategy":"fallback","validationCode":"Path f = instance.getLayout().getAssetIndexFile(assetId);\nboolean ok = Files.isRegularFile(f) && Files.size(f) > 2; // 'null'/'{}' are tiny\nif (!ok) downloadAssetIndex(assetId);","typeGuard":null,"tryCatchPattern":"try {\n    AssetIndex idx = instance.getAssetIndex(assetId);\n} catch (IOException e) {\n    LOG.warning(\"Asset index corrupt/missing, re-downloading: \" + e.getMessage());\n    downloadAssetIndex(assetId);\n    AssetIndex idx = instance.getAssetIndex(assetId);\n}","preventionTips":["Check asset index files for 0-byte size after downloads complete","Keep interrupted downloads atomic (temp file + move)","Re-verify assets after crashes instead of trusting on-disk state"],"tags":["io","json","minecraft-assets","corrupt-file"],"backgroundTag":"json-parse-error","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"}