HMCL-dev/HMCL · error · NoSuchGameInstanceException

${instanceId}

Error message

${instanceId}

What it means

putPrimaryJar() on DefaultGameRepositoryDraft stages a replacement primary JAR for an existing instance, but first validates that instanceId refers to a manifest the draft knows about. If not, it throws NoSuchGameInstanceException whose message is the instance id. The draft only tracks instances from its base snapshot plus ones created via this draft — unknown ids are rejected immediately.

Solutions

  1. Verify the instance exists with repository.getInstance(id) or by checking the draft's manifests before calling putPrimaryJar
  2. Create the instance via draft.put(...) first if it is genuinely new, then stage its primary jar
  3. Catch NoSuchGameInstanceException and prompt the user to select a valid instance rather than assuming the id is valid
  4. Reload the repository snapshot if instances may have changed since the draft was opened

Example fix

// before
draft.putPrimaryJar(instanceId, jarPath); // throws if unknown
// after
if (draft.hasManifest(instanceId)) { // or check via snapshot
    draft.putPrimaryJar(instanceId, jarPath);
} else {
    throw new IllegalArgumentException("Unknown instance: " + instanceId);
}
Defensive patterns

Strategy: type-guard

Validate before calling

boolean exists = repository.getInstanceIds().contains(instanceId);
if (!exists) throw new IllegalArgumentException("Unknown instance: " + instanceId);

Type guard

boolean knownInstance = draft.manifests().stream().anyMatch(m -> m.id().equals(instanceId));

Try / catch

try {
    draft.putPrimaryJar(instanceId, jar);
} catch (NoSuchGameInstanceException e) {
    LOG.warning("Instance not in this draft: " + e.getMessage());
}

Prevention

When it happens

Trigger: Calling putPrimaryJar with a GameInstanceID that was never created in the repository, was created by a different draft/session, was removed, or is a typo of a real id; also when the base repository was modified elsewhere after the snapshot was taken.

Common situations: Stale references held across draft sessions; an instance deleted by another part of the app while a draft is open; misspelled or lowercase/uppercase mismatched instance ids; tests/automation using fabricated ids.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/game/DefaultGameRepositoryDraft.java:129

    /// {@inheritDoc}
    @Override
    public boolean isCommitted() {
        return state == GameRepositoryDraft.State.COMMITTED;
    }

    /// {@inheritDoc}
    @Override
    public void put(GameInstanceManifest manifest) throws IOException {
        checkOpen();
        putManifest(manifest, true);
    }

    /// {@inheritDoc}
    @Override
    public void putPrimaryJar(GameInstanceID instanceId, Path source) throws IOException {
        checkOpen();
        if (!manifests.containsKey(instanceId)) {
            throw new NoSuchGameInstanceException(instanceId);
        }

        Path normalizedSource = source.toAbsolutePath().normalize();
        if (!Files.isRegularFile(normalizedSource)) {
            throw new IOException("Primary JAR source is not a regular file: " + normalizedSource);
        }

        Path target = getPrimaryJarTarget(instanceId);
        if (normalizedSource.equals(target)) {
            primaryJarSources.remove(instanceId);
        } else {
            primaryJarSources.put(instanceId, normalizedSource);
        }
    }

    /// {@inheritDoc}
    @Override
    public void remove(GameInstanceID instanceId) {

View on GitHub (pinned to 24702dc5a0)