{"record":{"id":"aeda06742415d92e","repo":"HMCL-dev/HMCL","slug":"selected-profile-changed-aeda06","errorCode":null,"errorMessage":"Selected profile changed","messagePattern":"Selected profile changed","errorType":"exception","errorClass":"ServerResponseMalformedException","httpStatus":null,"severity":"error","filePath":"HMCLCore/src/main/java/org/jackhuang/hmcl/auth/yggdrasil/YggdrasilAccount.java","lineNumber":122,"sourceCode":"    @Override\n    public synchronized AuthInfo logIn() throws AuthenticationException {\n        if (!authenticated || !session.hasProfileName()) {\n            if (session.hasProfileName() && service.validate(session.getAccessToken(), session.getClientToken())) {\n                authenticated = true;\n            } else {\n                YggdrasilSession acquiredSession;\n                try {\n                    acquiredSession = service.refresh(session.getAccessToken(), session.getClientToken(), null);\n                } catch (RemoteAuthenticationException e) {\n                    if (\"ForbiddenOperationException\".equals(e.getRemoteName())) {\n                        throw new CredentialExpiredException(e);\n                    } else {\n                        throw e;\n                    }\n                }\n                if (acquiredSession.getSelectedProfile() == null ||\n                        !acquiredSession.getSelectedProfile().getId().equals(profileID)) {\n                    throw new ServerResponseMalformedException(\"Selected profile changed\");\n                }\n                if (!acquiredSession.hasProfileName()) {\n                    throw new ServerResponseMalformedException(\"Profile name is missing\");\n                }\n\n                session = acquiredSession;\n\n                authenticated = true;\n                invalidate();\n            }\n        }\n\n        return session.toAuthInfo();\n    }\n\n    @Override\n    public synchronized AuthInfo logInWithPassword(String password) throws AuthenticationException {\n        YggdrasilSession acquiredSession = service.authenticate(loginName, password, randomClientToken());","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/yggdrasil/YggdrasilAccount.java#L104-L140","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\naccount.logIn(); // throws: stored profileID no longer matches server\n// after\nif (account.getProfileId() != null) {\n    try { account.logIn(); }\n    catch (ServerResponseMalformedException e) {\n        account.remove();\n        account = factory.create(server, username, password);\n        account.logIn();\n    }\n}","handlingStrategy":"try-catch","validationCode":"if (account.getProfileId() != null && !sessionHasProfileWithId(account.getProfileId())) {\n    // profile changed server-side: force full re-login instead of logIn()\n}","typeGuard":null,"tryCatchPattern":"try {\n    account.logIn();\n} catch (ServerResponseMalformedException e) {\n    // remove account and re-add / re-select a character\n    account.remove();\n    account = factory.create(...);\n}","preventionTips":["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."],"tags":["authentication","yggdrasil","session"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"24702dc5a0214034f4c27166d5fd30cad08cec19","analyzedAt":"2026-09-10T12:36:46.680Z","contentChangedAt":"2026-09-10T12:36:46.680Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}