asLody/VirtualApp · error · java.lang.IllegalArgumentException

authTokenType is null

Error message

authTokenType is null

What it means

setAuthToken(userId, account, authTokenType, authToken) throws IllegalArgumentException('authTokenType is null') after the account null-check. The authTokenType is the map key under which the token is stored on the VAccount; a null key would make token lookup and Map operations unreliable, so the service rejects it.

Solutions

  1. Pass a non-empty authTokenType string constant (e.g. 'com.example.token')
  2. Validate the value read from Bundle/intent extras before calling setAuthToken
  3. Define token types as compile-time constants rather than runtime-computed strings

Example fix

// before
manager.setAuthToken(userId, account, extras.getString("token_type"), token);
// after
String tokenType = extras.getString("token_type");
if (account != null && tokenType != null) {
    manager.setAuthToken(userId, account, tokenType, token);
}
Defensive patterns

Strategy: validation

Validate before calling

if (authTokenType == null || authTokenType.isEmpty()) { throw new IllegalStateException("authTokenType must be a non-empty constant"); }

Type guard

boolean isValidTokenType(String t) { return t != null && !t.trim().isEmpty(); }

Prevention

When it happens

Trigger: Calling setAuthToken with a null authTokenType — e.g. the token type comes from a Bundle extra that was never set (AccountManager.KEY_AUTHENTICATOR_TYPES or a custom constant missing), or a constant defined as null.

Common situations: Custom authenticator code where the token-type string constant was renamed or its config value lost; reading the type from an intent extra that is absent; typos making the variable unassigned.

Related errors


AI-assisted analysis of asLody/VirtualApp@666fefcb5d (2026-09-09). Data as JSON: /api/errors/1170c0acb6b33c3c. Report an issue: GitHub.

Appendix: source

Thrown at VirtualApp/lib/src/main/java/com/lody/virtual/server/accounts/VAccountManagerService.java:347

                saveAllAccounts();
                synchronized (authTokenRecords) {
                    Iterator<AuthTokenRecord> iterator = authTokenRecords.iterator();
                    while (iterator.hasNext()) {
                        AuthTokenRecord record = iterator.next();
                        if (record.userId == userId && record.account.equals(account)) {
                            iterator.remove();
                        }
                    }
                }
                sendAccountsChangedBroadcast(userId);
            }
        }
    }

    @Override
    public void setAuthToken(int userId, Account account, String authTokenType, String authToken) {
        if (account == null) throw new IllegalArgumentException("account is null");
        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
        synchronized (accountsByUserId) {
            VAccount vAccount = getAccount(userId, account);
            if (vAccount != null) {
                // FIXME: cancelNotification
                vAccount.authTokens.put(authTokenType, authToken);
                this.saveAllAccounts();
            }
        }
    }


    @Override
    public void setUserData(int userId, Account account, String key, String value) {
        if (key == null) throw new IllegalArgumentException("key is null");
        if (account == null) throw new IllegalArgumentException("account is null");
        VAccount vAccount = getAccount(userId, account);
        if (vAccount != null) {
            synchronized (accountsByUserId) {

View on GitHub (pinned to 666fefcb5d)