MuntashirAkon/AppManager · error · KeyStoreException

Stored pass is empty for alias

Error message

Stored pass is empty for alias ${alias}

What it means

getAliasPassword checks whether an encrypted password exists for the given keystore alias via sSharedPreferences.contains(prefAlias). If the subsequent getString returns null despite contains() being true, it throws KeyStoreException "Stored pass is empty for alias ..." — the stored value is null or the pref entry is corrupt.

Solutions

  1. Remove the corrupt pref entry and re-save the alias password so it is stored as a String.
  2. Verify nothing writes the alias pref with a non-String type (contains() is true but getString returns null).
  3. Wrap the read in a null check that falls back to prompting the user for the password instead of failing.

Example fix

// before
String encryptedPass = sSharedPreferences.getString(prefAlias, null);
if (encryptedPass == null) {
    throw new KeyStoreException("Stored pass is empty for alias " + alias);
}
// after
String encryptedPass = sSharedPreferences.getString(prefAlias, null);
if (encryptedPass == null) {
    sSharedPreferences.edit().remove(prefAlias).apply(); // clear corrupt entry
    encryptedPass = promptAndEncryptPassword(alias);    // re-store as String
    if (encryptedPass == null) throw new KeyStoreException("Stored pass is empty for alias " + alias);
}
Defensive patterns

Strategy: validation

Validate before calling

// before calling getAliasPassword/getKey
String prefAlias = getPrefAlias(alias);
String stored = sSharedPreferences.getString(prefAlias, null);
if (stored == null || stored.isEmpty()) {
    // prompt user for the alias password and save it first
    saveAliasPassword(alias, promptForPassword(alias));
}

Try / catch

// try
try {
    char[] pass = keyStoreManager.getKey(alias);
} catch (KeyStoreException e) {
    if (e.getMessage().contains("Stored pass is empty")) {
        // corrupt/typed pref entry: clear and re-store
        removeAliasPasswordPref(alias);
        promptAndStoreAliasPassword(alias);
    }
}

Prevention

When it happens

Trigger: Calling getAliasPassword(alias) (directly or via getKey) when sSharedPreferences.contains(getPrefAlias(alias)) is true but getString(prefAlias, null) returns null.

Common situations: Prefs XML manually edited or partially written; type mismatch after pref written with a different type (e.g. as a Set) so getString returns null; concurrent write/clear during read.

Understand the failure class

Background: "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank — this error's family across 48 libraries.

Related errors


AI-assisted analysis of MuntashirAkon/AppManager@0152f468fc (2026-09-12). Data as JSON: /api/errors/1fdbd1cd558f486f. Report an issue: GitHub.

Appendix: source

Thrown at app/src/main/java/io/github/muntashirakon/AppManager/crypto/ks/KeyStoreManager.java:499

            throw new KeyStoreException("Could not decrypt encrypted password.");
        }
        return realPassword;
    }

    /**
     * @return Password for the given alias. {@link Utils#clearChars(char[])} must be called when done.
     * @deprecated Kept for migratory purposes only, deprecated since v2.6.3. To be removed in v3.0.0.
     */
    @Deprecated
    @CheckResult
    @NonNull
    private char[] getAliasPassword(@NonNull String alias) throws KeyStoreException {
        char[] password;
        String prefAlias = getPrefAlias(alias);
        if (sSharedPreferences.contains(prefAlias)) {
            String encryptedPass = sSharedPreferences.getString(prefAlias, null);
            if (encryptedPass == null) {
                throw new KeyStoreException("Stored pass is empty for alias " + alias);
            }
            password = getDecryptedPassword(mContext, encryptedPass);
            if (password == null) {
                throw new KeyStoreException("Decrypted pass is empty for alias " + alias);
            }
            return password;
        } else {
            IntentFilter filter = new IntentFilter(ACTION_KS_INTERACTION_BEGIN);
            filter.addAction(ACTION_KS_INTERACTION_END);
            ContextCompat.registerReceiver(mContext, mReceiver, filter, ContextCompat.RECEIVER_NOT_EXPORTED);
            Intent broadcastIntent = new Intent(ACTION_KS_INTERACTION_BEGIN);
            broadcastIntent.setPackage(mContext.getPackageName());
            mContext.sendBroadcast(broadcastIntent);
            // Intent wrapper
            Intent intent = new Intent(mContext, KeyStoreActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.putExtra(KeyStoreActivity.EXTRA_ALIAS, alias);
            String ks = "AM KeyStore";

View on GitHub (pinned to 0152f468fc)