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
- Verify the instance exists with repository.getInstance(id) or by checking the draft's manifests before calling putPrimaryJar
- Create the instance via draft.put(...) first if it is genuinely new, then stage its primary jar
- Catch NoSuchGameInstanceException and prompt the user to select a valid instance rather than assuming the id is valid
- 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
- Reopen the draft after instances change elsewhere
- Look up ids from the repository instead of caching them across sessions
- Compare ids case-sensitively — GameInstanceID is exact-match
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
- ${from}
- Primary JAR source is not a regular file
- ${targetRoot}
- An unregistered instance directory already exists
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)