{"record":{"id":"3b6be47a086f8c76","repo":"HMCL-dev/HMCL","slug":"storage-does-not-have-api-root","errorCode":null,"errorMessage":"storage does not have API root.","messagePattern":"storage does not have API root\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"HMCLCore/src/main/java/org/jackhuang/hmcl/auth/authlibinjector/AuthlibInjectorAccountFactory.java","lineNumber":72,"sourceCode":"    @Override\n    public AuthlibInjectorAccount create(CharacterSelector selector, String username, String password, ProgressCallback progressCallback, Object additionalData) throws AuthenticationException {\n        Objects.requireNonNull(selector);\n        Objects.requireNonNull(username);\n        Objects.requireNonNull(password);\n\n        AuthlibInjectorServer server = (AuthlibInjectorServer) additionalData;\n\n        return new AuthlibInjectorAccount(server, downloader, username, password, selector);\n    }\n\n    @Override\n    public AuthlibInjectorAccount fromStorage(JsonObject metadata, JsonObject privateData) {\n        Objects.requireNonNull(metadata);\n        Objects.requireNonNull(privateData);\n\n        String apiRoot = JsonUtils.getString(metadata, \"serverBaseURL\");\n        if (apiRoot == null) {\n            throw new IllegalArgumentException(\"storage does not have API root.\");\n        }\n        AuthlibInjectorServer server = serverLookup.apply(apiRoot);\n        return fromStorage(metadata, privateData, downloader, server);\n    }\n\n    static AuthlibInjectorAccount fromStorage(\n            JsonObject metadata,\n            JsonObject privateData,\n            AuthlibInjectorArtifactProvider downloader,\n            AuthlibInjectorServer server) {\n        AccountID accountID = Account.readAccountID(metadata);\n        YggdrasilSession session = YggdrasilSession.fromStorage(metadata, privateData);\n\n        String loginName = JsonUtils.getString(metadata, \"loginName\");\n        if (loginName == null) {\n            throw new IllegalArgumentException(\"storage does not have loginName\");\n        }\n","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/authlibinjector/AuthlibInjectorAccountFactory.java#L54-L90","documentation":"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.","triggerScenarios":"Calling fromStorage(JsonObject metadata, JsonObject privateData) with metadata lacking the \"serverBaseURL\" key.","commonSituations":"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.","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"],"exampleFix":"// before\nfactory.fromStorage(metadata, privateData); // metadata has no serverBaseURL\n// after\nif (metadata.has(\"serverBaseURL\")) {\n    factory.fromStorage(metadata, privateData);\n}","handlingStrategy":"validation","validationCode":"if (metadata == null || !metadata.has(\"serverBaseURL\")) {\n    throw new IllegalArgumentException(\"Persisted account missing serverBaseURL; re-add account\");\n}\nAuthlibInjectorAccount account = factory.fromStorage(metadata, privateData);","typeGuard":null,"tryCatchPattern":"try {\n    return factory.fromStorage(metadata, privateData);\n} catch (IllegalArgumentException e) {\n    log.warn(\"Incomplete authlib-injector account storage: {}\", e.getMessage());\n    return null;\n}","preventionTips":["Always persist serverBaseURL when saving accounts","Re-add accounts missing server data instead of forcing deserialization","Validate storage keys after version migrations"],"tags":["minecraft","authlib-injector","persistence","json"],"backgroundTag":"missing-required-argument","analyzedSha":"24702dc5a0214034f4c27166d5fd30cad08cec19","analyzedAt":"2026-09-10T12:36:46.680Z","contentChangedAt":"2026-09-10T12:36:46.680Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}