HMCL-dev/HMCL · error · IllegalArgumentException

is missing

Error message

 is missing

What it means

Helper requireStorageString throws '<name> is missing' when a required string ('clientToken' or 'accessToken') is absent from the stored private data JSON. It enforces that persisted credentials needed to rebuild a YggdrasilSession are present.

Solutions

  1. Re-add the missing 'clientToken'/'accessToken' key to the private data JSON
  2. Remove the corrupt account entry and log in again to regenerate credentials
  3. Restore the storage file from backup

Example fix

// before
String token = requireStorageString(privateData, "accessToken"); // throws if absent
// after
if (JsonUtils.getString(privateData, "accessToken") == null) {
    privateData = reloginAndRebuildPrivateData();
}
String token = requireStorageString(privateData, "accessToken");
Defensive patterns

Strategy: validation

Validate before calling

for (String key : List.of("clientToken", "accessToken"))
    if (JsonUtils.getString(privateData, key) == null)
        throw new IllegalArgumentException("Private data missing " + key);

Type guard

static boolean hasCredentials(JsonObject privateData) {
    return JsonUtils.getString(privateData, "clientToken") != null
        && JsonUtils.getString(privateData, "accessToken") != null;
}

Try / catch

try {
    session = YggdrasilSession.fromStorage(metadata, privateData);
} catch (IllegalArgumentException e) {
    LOG.warning("Missing stored credential: " + e.getMessage());
    session = relogin();
}

Prevention

When it happens

Trigger: Calling fromStorage whose privateData JsonObject lacks 'clientToken' or 'accessToken', so requireStorageString returns null and throws with the field name plus ' is missing'.

Common situations: Hand-edited or truncated accounts.json, partial writes on crash, or external tools stripping credential fields.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/auth/yggdrasil/YggdrasilSession.java:115

                ? GSON_PROPERTIES.fromJson(userPropertiesObject, JsonUtils.mapTypeOf(String.class, String.class))
                : null;
        return new YggdrasilSession(clientToken, accessToken, new GameProfile(profileID, profileName), null, userProperties);
    }

    public void writePrivateData(JsonObject privateData) {
        if (selectedProfile == null)
            throw new IllegalStateException("No character is selected");

        privateData.addProperty("clientToken", clientToken);
        privateData.addProperty("accessToken", accessToken);
        privateData.addProperty("profileName", selectedProfile.getName());
        privateData.add("userProperties", GSON_PROPERTIES.toJsonTree(userProperties));
    }

    private static String requireStorageString(JsonObject storage, String name) {
        String value = JsonUtils.getString(storage, name);
        if (value == null) {
            throw new IllegalArgumentException(name + " is missing");
        }
        return value;
    }

    public AuthInfo toAuthInfo() {
        if (selectedProfile == null)
            throw new IllegalStateException("No character is selected");

        return new AuthInfo(selectedProfile.getName(), selectedProfile.getId(), accessToken, AuthInfo.USER_TYPE_MSA,
                Optional.ofNullable(userProperties)
                        .map(properties -> properties.entrySet().stream()
                                .collect(Collectors.toMap(Map.Entry::getKey,
                                        e -> Collections.singleton(e.getValue()))))
                        .map(GSON_PROPERTIES::toJson).orElse("{}"));
    }

    private static final Gson GSON_PROPERTIES = new Gson();
}

View on GitHub (pinned to 24702dc5a0)