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
- Pass a non-null key string literal or constant
- Validate any dynamically-loaded key (resources/config) before calling
- 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
- Keep userdata keys as named constants in one place
- Validate keys loaded from resources/config (getString can return null)
- Validate key before account since the service checks key first
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)