HMCL-dev/HMCL · error · ServerResponseMalformedException
Failed to select character
Error message
Failed to select character
What it means
YggdrasilService.refresh throws ServerResponseMalformedException("Failed to select character") when a characterToSelect was requested but the refresh response's selectedProfile is null or has a different id. It means the server did not (or could not) bind the refreshed token to the requested character.
Solutions
- Re-authenticate (authenticate instead of refresh) and re-select a currently available character from availableProfiles.
- Pass null as characterToSelect if you don't require a specific character after refresh.
- Verify the character still exists on the auth server and re-add the account bound to a valid one.
Example fix
// before
service.refresh(accessToken, oldCharacter); // throws if character gone
// after
try {
service.refresh(accessToken, oldCharacter);
} catch (ServerResponseMalformedException e) {
YggdrasilSession fresh = service.authenticate(username, password);
// reselect from fresh.getAvailableProfiles()
} Defensive patterns
Strategy: try-catch
Validate before calling
if (characterToSelect != null &&
!availableProfileIds().contains(characterToSelect.getId())) {
// character no longer exists server-side; skip selection
characterToSelect = null;
} Try / catch
try {
service.refresh(accessToken, characterToSelect);
} catch (ServerResponseMalformedException e) {
// re-authenticate and reselect from availableProfiles
YggdrasilSession fresh = service.authenticate(username, password);
} Prevention
- Confirm the character still exists before calling refresh with a selection.
- Fetch availableProfiles after refresh failures to see valid characters.
- Avoid sharing one account across machines that may delete characters.
When it happens
Trigger: Calling refresh(token, characterToSelect) where the character was deleted/renamed on the server, or the server ignores the selectedCharacter hint in its /refresh response.
Common situations: Switching characters on an authlib-injector server whose backend deleted the old one; account kept on another machine while the character was removed; server implementations not honoring the selectedCharacter field.
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
- Selected profile changed
- Profile name is missing
- 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/17238b1028387724.
Report an issue: GitHub.
Appendix: source
Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/auth/yggdrasil/YggdrasilService.java:116
public YggdrasilSession refresh(String accessToken, String clientToken, GameProfile characterToSelect) throws AuthenticationException {
Objects.requireNonNull(accessToken);
Objects.requireNonNull(clientToken);
Map<String, Object> request = createRequestWithCredentials(accessToken, clientToken);
request.put("requestUser", true);
if (characterToSelect != null) {
request.put("selectedProfile", mapOf(
pair("id", UUIDs.toCompactString(characterToSelect.getId())),
pair("name", characterToSelect.getName())));
}
YggdrasilSession response = handleAuthenticationResponse(request(provider.getRefreshmentURL(), request), clientToken);
if (characterToSelect != null) {
if (response.getSelectedProfile() == null ||
!response.getSelectedProfile().getId().equals(characterToSelect.getId())) {
throw new ServerResponseMalformedException("Failed to select character");
}
}
return response;
}
public boolean validate(String accessToken) throws AuthenticationException {
return validate(accessToken, null);
}
public boolean validate(String accessToken, String clientToken) throws AuthenticationException {
Objects.requireNonNull(accessToken);
try {
requireEmpty(request(provider.getValidationURL(), createRequestWithCredentials(accessToken, clientToken)));
return true;
} catch (RemoteAuthenticationException e) {
if ("ForbiddenOperationException".equals(e.getRemoteName())) {View on GitHub (pinned to 24702dc5a0)