asLody/VirtualApp · error · java.lang.IllegalArgumentException

key is null

Error message

key is null

What it means

setUserData(userId, account, key, value) throws IllegalArgumentException('key is null') as its first guard. User data is stored in a per-account map keyed by 'key', so a null key is invalid before any account resolution happens. Android's AccountManager has the same requirement for setUserData.

Solutions

  1. Pass a non-null key string literal or constant
  2. Validate any dynamically-loaded key (resources/config) before calling
  3. Check key non-null before account handling since key is validated first

Example fix

// before
manager.setUserData(userId, account, key, value);
// after
if (key == null || account == null) {
    Log.w(TAG, "setUserData skipped: key/account null");
    return;
}
manager.setUserData(userId, account, key, value);
Defensive patterns

Strategy: validation

Validate before calling

if (key == null || key.isEmpty()) { throw new IllegalStateException("userdata key required"); }

Type guard

boolean canSetUserData(String key, Account a) { return key != null && !key.isEmpty() && a != null; }

Prevention

When it happens

Trigger: Calling setUserData with a null key — typically a userdata constant read from config/resources that resolved to null, or a variable holding the key never initialized.

Common situations: Storing profile flags (e.g. 'user_id', 'sync_enabled') where the constant string was mistyped; resources/string lookups returning null; reflection-driven key names missing at runtime.

Related errors


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

Appendix: source

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

    @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) {
                vAccount.userDatas.put(key, value);
                saveAllAccounts();
            }
        }
    }


    @Override
    public void hasFeatures(int userId, IAccountManagerResponse response,
                            final Account account, final String[] features) {
        if (response == null) throw new IllegalArgumentException("response is null");
        if (account == null) throw new IllegalArgumentException("account is null");
        if (features == null) throw new IllegalArgumentException("features is null");
        AuthenticatorInfo info = this.getAuthenticatorInfo(account.type);

View on GitHub (pinned to 666fefcb5d)