HMCL-dev/HMCL · error · IOException

Unrecognized asset object

Error message

Unrecognized asset object ${name} in asset ${assetId} of version ${id}

What it means

DefaultGameInstance.getAssetObject(name, assetId, id) resolves an asset object name from the asset index to a concrete file path. Any unexpected exception (beyond plain IOException) while looking up or reconstructing the asset object is wrapped in an IOException 'Unrecognized asset object <name> in asset <assetId> of version <id>'. It signals the asset index lacks an entry for the requested object or its stored metadata cannot be interpreted.

Solutions

  1. Confirm the asset object name exists in assets/indexes/<assetId>.json; if not, use the correct assetId for the Minecraft version being launched
  2. Re-download the full asset index for that version so all entries are present
  3. Catch the IOException, log name/assetId/id, and re-run asset verification (download missing assets) before retrying
  4. Avoid mixing version ids and assetIds from different Minecraft versions when calling getAssetObject

Example fix

// before
Optional<Path> obj = instance.getAssetObject(name, "legacy", "1.7.10");
// after
// use the assetId actually declared by the version json
String assetId = versionJson.getAssets();
Optional<Path> obj = instance.getAssetObject(name, assetId, "1.7.10");
Defensive patterns

Strategy: try-catch

Validate before calling

AssetIndex idx = instance.getAssetIndex(assetId);
boolean known = idx.getObject(name) != null; // verify entry exists before resolving path

Try / catch

try {
    Optional<Path> obj = instance.getAssetObject(name, assetId, versionId);
} catch (IOException e) {
    LOG.warning("Unresolved asset " + name + " for " + assetId + ", running asset verification");
    verifyAndDownloadAssets(assetId);
}

Prevention

When it happens

Trigger: Requesting an asset object whose hash/entry is absent from the parsed AssetIndex; AssetIndex throwing during virtual/legacy layout reconstruction; malformed asset index entries encountered while resolving the name.

Common situations: Mod or launcher code referencing a resource key not present in the version's asset index; mixing asset indexes between Minecraft versions (old version id with a newer assetId); partially repaired/corrupt asset index json missing entries.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10). Data as JSON: /api/errors/1d2ddb82f209479a. Report an issue: GitHub.

Appendix: source

Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/game/DefaultGameInstance.java:328

            return reconstructAssets(assetId);
        } catch (IOException | JsonParseException e) {
            LOG.error("Unable to reconstruct asset directory", e);
            return getLayout().getAssetDirectory();
        }
    }

    /// {@inheritDoc}
    @Override
    public Optional<Path> getAssetObject(String assetId, String name) throws IOException {
        try {
            @Nullable AssetObject assetObject = getAssetIndex(assetId).getObjects().get(name);
            return assetObject != null
                    ? Optional.of(getLayout().getAssetObject(assetObject))
                    : Optional.empty();
        } catch (IOException e) {
            throw e;
        } catch (Exception e) {
            throw new IOException(
                    "Unrecognized asset object " + name + " in asset " + assetId + " of version " + id,
                    e);
        }
    }

    /// Reconstructs virtual and legacy resource layouts for an asset index when required.
    ///
    /// @param assetId the asset index ID
    /// @return the directory to supply at launch time
    /// @throws IOException        if an asset cannot be copied
    /// @throws JsonParseException if the asset index is malformed
    private Path reconstructAssets(String assetId) throws IOException, JsonParseException {
        Path assetsDir = getLayout().getAssetDirectory();
        Path indexFile = getLayout().getAssetIndexFile(assetId);
        Path virtualRoot = assetsDir.resolve("virtual").resolve(assetId);

        if (!Files.isRegularFile(indexFile)) {
            return assetsDir;

View on GitHub (pinned to 24702dc5a0)