HMCL-dev/HMCL · error · ServerResponseMalformedException

Profile name is missing

Error message

Profile name is missing

What it means

YggdrasilAccount.logIn throws ServerResponseMalformedException("Profile name is missing") when the acquired session has a selected profile but YggdrasilSession.hasProfileName() reports no name. A session without a profile name cannot produce valid game launch credentials, so HMCL rejects it.

Solutions

  1. Check the auth server's /authenticate or /refresh response includes "name" in selectedProfile; fix the server if you control it.
  2. Re-login from scratch (remove and re-add the account) to force a fresh full authentication.
  3. Switch to a different authentication server implementation that returns complete profile objects.

Example fix

// before (server response)
{"selectedProfile":{"id":"069a79f4..."}}
// after
{"selectedProfile":{"id":"069a79f4...","name":"Notch"}}
Defensive patterns

Strategy: try-catch

Validate before calling

JsonObject selected = response.getAsJsonObject("selectedProfile");
if (selected == null || !selected.has("name")) {
    throw new IllegalStateException("Server returned selected profile without name");
}

Try / catch

try {
    account.logIn();
} catch (ServerResponseMalformedException e) {
    // full re-login or switch to a functioning auth server
    account.remove();
}

Prevention

When it happens

Trigger: logIn() receiving a server response whose selectedProfile object contains an id but a null/missing "name" field, or a response with selectedProfile null after token validate/refresh.

Common situations: Broken third-party auth servers returning partial profile objects; proxies or API changes stripping the name field; authlib-injector backends with incomplete profile data.

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


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

Appendix: source

Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/auth/yggdrasil/YggdrasilAccount.java:125

            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());

        if (acquiredSession.getSelectedProfile() == null) {
            if (acquiredSession.getAvailableProfiles() == null || acquiredSession.getAvailableProfiles().isEmpty()) {

View on GitHub (pinned to 24702dc5a0)