HMCL-dev/HMCL · error · IllegalArgumentException
storage does not have API root.
Error message
storage does not have API root.
What it means
AuthlibInjectorAccountFactory.fromStorage rebuilds an authlib-injector account from persisted metadata. It reads the serverBaseURL key; if absent it throws IllegalArgumentException because the account cannot be reattached to its authlib-injector server without the API root. This guards against corrupt/incomplete persisted account data.
Solutions
- Ensure metadata contains serverBaseURL pointing to the authlib-injector server before deserialization
- Re-add the account via normal login so storage is regenerated with serverBaseURL
- Migrate old storage by copying the server URL into the serverBaseURL key
Example fix
// before
factory.fromStorage(metadata, privateData); // metadata has no serverBaseURL
// after
if (metadata.has("serverBaseURL")) {
factory.fromStorage(metadata, privateData);
} Defensive patterns
Strategy: validation
Validate before calling
if (metadata == null || !metadata.has("serverBaseURL")) {
throw new IllegalArgumentException("Persisted account missing serverBaseURL; re-add account");
}
AuthlibInjectorAccount account = factory.fromStorage(metadata, privateData); Try / catch
try {
return factory.fromStorage(metadata, privateData);
} catch (IllegalArgumentException e) {
log.warn("Incomplete authlib-injector account storage: {}", e.getMessage());
return null;
} Prevention
- Always persist serverBaseURL when saving accounts
- Re-add accounts missing server data instead of forcing deserialization
- Validate storage keys after version migrations
When it happens
Trigger: Calling fromStorage(JsonObject metadata, JsonObject privateData) with metadata lacking the "serverBaseURL" key.
Common situations: Hand-edited or partially migrated accounts.json; storage entries created by a different launcher or older schema; deleting server entries while accounts still reference them.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- storage does not have loginName
- accountID is missing
- Malformed response\n" + text
- authlib-injectors.json -> urls cannot be null.
- "Invalid metadata file: " + jarInJarMetadata
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/3b6be47a086f8c76.
Report an issue: GitHub.
Appendix: source
Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/auth/authlibinjector/AuthlibInjectorAccountFactory.java:72
@Override
public AuthlibInjectorAccount create(CharacterSelector selector, String username, String password, ProgressCallback progressCallback, Object additionalData) throws AuthenticationException {
Objects.requireNonNull(selector);
Objects.requireNonNull(username);
Objects.requireNonNull(password);
AuthlibInjectorServer server = (AuthlibInjectorServer) additionalData;
return new AuthlibInjectorAccount(server, downloader, username, password, selector);
}
@Override
public AuthlibInjectorAccount fromStorage(JsonObject metadata, JsonObject privateData) {
Objects.requireNonNull(metadata);
Objects.requireNonNull(privateData);
String apiRoot = JsonUtils.getString(metadata, "serverBaseURL");
if (apiRoot == null) {
throw new IllegalArgumentException("storage does not have API root.");
}
AuthlibInjectorServer server = serverLookup.apply(apiRoot);
return fromStorage(metadata, privateData, downloader, server);
}
static AuthlibInjectorAccount fromStorage(
JsonObject metadata,
JsonObject privateData,
AuthlibInjectorArtifactProvider downloader,
AuthlibInjectorServer server) {
AccountID accountID = Account.readAccountID(metadata);
YggdrasilSession session = YggdrasilSession.fromStorage(metadata, privateData);
String loginName = JsonUtils.getString(metadata, "loginName");
if (loginName == null) {
throw new IllegalArgumentException("storage does not have loginName");
}
View on GitHub (pinned to 24702dc5a0)