{"record":{"id":"69febeacc059ba01","repo":"HMCL-dev/HMCL","slug":"is-missing-69febe","errorCode":null,"errorMessage":" is missing","messagePattern":" is missing","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"HMCLCore/src/main/java/org/jackhuang/hmcl/auth/yggdrasil/YggdrasilSession.java","lineNumber":115,"sourceCode":"                ? GSON_PROPERTIES.fromJson(userPropertiesObject, JsonUtils.mapTypeOf(String.class, String.class))\n                : null;\n        return new YggdrasilSession(clientToken, accessToken, new GameProfile(profileID, profileName), null, userProperties);\n    }\n\n    public void writePrivateData(JsonObject privateData) {\n        if (selectedProfile == null)\n            throw new IllegalStateException(\"No character is selected\");\n\n        privateData.addProperty(\"clientToken\", clientToken);\n        privateData.addProperty(\"accessToken\", accessToken);\n        privateData.addProperty(\"profileName\", selectedProfile.getName());\n        privateData.add(\"userProperties\", GSON_PROPERTIES.toJsonTree(userProperties));\n    }\n\n    private static String requireStorageString(JsonObject storage, String name) {\n        String value = JsonUtils.getString(storage, name);\n        if (value == null) {\n            throw new IllegalArgumentException(name + \" is missing\");\n        }\n        return value;\n    }\n\n    public AuthInfo toAuthInfo() {\n        if (selectedProfile == null)\n            throw new IllegalStateException(\"No character is selected\");\n\n        return new AuthInfo(selectedProfile.getName(), selectedProfile.getId(), accessToken, AuthInfo.USER_TYPE_MSA,\n                Optional.ofNullable(userProperties)\n                        .map(properties -> properties.entrySet().stream()\n                                .collect(Collectors.toMap(Map.Entry::getKey,\n                                        e -> Collections.singleton(e.getValue()))))\n                        .map(GSON_PROPERTIES::toJson).orElse(\"{}\"));\n    }\n\n    private static final Gson GSON_PROPERTIES = new Gson();\n}","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/yggdrasil/YggdrasilSession.java#L97-L133","documentation":"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.","triggerScenarios":"Calling fromStorage whose privateData JsonObject lacks 'clientToken' or 'accessToken', so requireStorageString returns null and throws with the field name plus ' is missing'.","commonSituations":"Hand-edited or truncated accounts.json, partial writes on crash, or external tools stripping credential fields.","solutions":["Re-add the missing 'clientToken'/'accessToken' key to the private data JSON","Remove the corrupt account entry and log in again to regenerate credentials","Restore the storage file from backup"],"exampleFix":"// before\nString token = requireStorageString(privateData, \"accessToken\"); // throws if absent\n// after\nif (JsonUtils.getString(privateData, \"accessToken\") == null) {\n    privateData = reloginAndRebuildPrivateData();\n}\nString token = requireStorageString(privateData, \"accessToken\");","handlingStrategy":"validation","validationCode":"for (String key : List.of(\"clientToken\", \"accessToken\"))\n    if (JsonUtils.getString(privateData, key) == null)\n        throw new IllegalArgumentException(\"Private data missing \" + key);","typeGuard":"static boolean hasCredentials(JsonObject privateData) {\n    return JsonUtils.getString(privateData, \"clientToken\") != null\n        && JsonUtils.getString(privateData, \"accessToken\") != null;\n}","tryCatchPattern":"try {\n    session = YggdrasilSession.fromStorage(metadata, privateData);\n} catch (IllegalArgumentException e) {\n    LOG.warning(\"Missing stored credential: \" + e.getMessage());\n    session = relogin();\n}","preventionTips":["Guard against truncated writes of the storage file (atomic write + rename)","Validate credential fields when loading accounts before use","Re-authenticate instead of hand-restoring tokens"],"tags":["java","minecraft","credentials","json"],"backgroundTag":"missing-required-config-field","analyzedSha":"24702dc5a0214034f4c27166d5fd30cad08cec19","analyzedAt":"2026-09-10T12:36:46.680Z","contentChangedAt":"2026-09-10T12:36:46.680Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}