HMCL-dev/HMCL · error · ServerResponseMalformedException
Selected profile changed
Error message
Selected profile changed
What it means
YggdrasilAccount.logIn throws ServerResponseMalformedException("Selected profile changed") when the refreshed/validated session's selected profile UUID differs from the account's stored profileID. HMCL treats this as a tampered or inconsistent server response, since the server must return the same character the account is bound to.
Solutions
- Remove the account from the launcher and re-add it (full login) so it re-binds to the current character.
- Select a different character via the account's character-selection flow if the server offers availableProfiles.
- Verify you are authenticating against the same yggdrasil server the account was created on.
Example fix
// before
account.logIn(); // throws: stored profileID no longer matches server
// after
if (account.getProfileId() != null) {
try { account.logIn(); }
catch (ServerResponseMalformedException e) {
account.remove();
account = factory.create(server, username, password);
account.logIn();
}
} Defensive patterns
Strategy: try-catch
Validate before calling
if (account.getProfileId() != null && !sessionHasProfileWithId(account.getProfileId())) {
// profile changed server-side: force full re-login instead of logIn()
} Try / catch
try {
account.logIn();
} catch (ServerResponseMalformedException e) {
// remove account and re-add / re-select a character
account.remove();
account = factory.create(...);
} Prevention
- Avoid deleting characters on the auth server while the launcher account is bound to them.
- Keep the account and its auth server origin consistent (no switching backends).
- Re-login after server migrations instead of relying on token refresh.
When it happens
Trigger: Calling logIn() (which performs token refresh/validate) after the account's selected character was deleted, replaced, or changed server-side so the returned selectedProfile id no longer equals the stored profileID.
Common situations: Character deleted on the auth server while the launcher still references it; switching auth servers/authlib-injector backends that reuse tokens differently; duplicated account entries after migration.
Understand the failure class
Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.
Related errors
- Profile name is missing
- Failed to select character
- Selected profile changed
- uhs mismatched
- Client token changed from
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/aeda06742415d92e.
Report an issue: GitHub.
Appendix: source
Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/auth/yggdrasil/YggdrasilAccount.java:122
@Override
public synchronized AuthInfo logIn() throws AuthenticationException {
if (!authenticated || !session.hasProfileName()) {
if (session.hasProfileName() && service.validate(session.getAccessToken(), session.getClientToken())) {
authenticated = true;
} else {
YggdrasilSession acquiredSession;
try {
acquiredSession = service.refresh(session.getAccessToken(), session.getClientToken(), null);
} catch (RemoteAuthenticationException e) {
if ("ForbiddenOperationException".equals(e.getRemoteName())) {
throw new CredentialExpiredException(e);
} else {
throw e;
}
}
if (acquiredSession.getSelectedProfile() == null ||
!acquiredSession.getSelectedProfile().getId().equals(profileID)) {
throw new ServerResponseMalformedException("Selected profile changed");
}
if (!acquiredSession.hasProfileName()) {
throw new ServerResponseMalformedException("Profile name is missing");
}
session = acquiredSession;
authenticated = true;
invalidate();
}
}
return session.toAuthInfo();
}
@Override
public synchronized AuthInfo logInWithPassword(String password) throws AuthenticationException {
YggdrasilSession acquiredSession = service.authenticate(loginName, password, randomClientToken());View on GitHub (pinned to 24702dc5a0)