{"record":{"id":"1fdbd1cd558f486f","repo":"MuntashirAkon/AppManager","slug":"stored-pass-is-empty-for-alias-alias","errorCode":null,"errorMessage":"Stored pass is empty for alias ${alias}","messagePattern":"Stored pass is empty for alias (.+?)","errorType":"exception","errorClass":"KeyStoreException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/io/github/muntashirakon/AppManager/crypto/ks/KeyStoreManager.java","lineNumber":499,"sourceCode":"            throw new KeyStoreException(\"Could not decrypt encrypted password.\");\n        }\n        return realPassword;\n    }\n\n    /**\n     * @return Password for the given alias. {@link Utils#clearChars(char[])} must be called when done.\n     * @deprecated Kept for migratory purposes only, deprecated since v2.6.3. To be removed in v3.0.0.\n     */\n    @Deprecated\n    @CheckResult\n    @NonNull\n    private char[] getAliasPassword(@NonNull String alias) throws KeyStoreException {\n        char[] password;\n        String prefAlias = getPrefAlias(alias);\n        if (sSharedPreferences.contains(prefAlias)) {\n            String encryptedPass = sSharedPreferences.getString(prefAlias, null);\n            if (encryptedPass == null) {\n                throw new KeyStoreException(\"Stored pass is empty for alias \" + alias);\n            }\n            password = getDecryptedPassword(mContext, encryptedPass);\n            if (password == null) {\n                throw new KeyStoreException(\"Decrypted pass is empty for alias \" + alias);\n            }\n            return password;\n        } else {\n            IntentFilter filter = new IntentFilter(ACTION_KS_INTERACTION_BEGIN);\n            filter.addAction(ACTION_KS_INTERACTION_END);\n            ContextCompat.registerReceiver(mContext, mReceiver, filter, ContextCompat.RECEIVER_NOT_EXPORTED);\n            Intent broadcastIntent = new Intent(ACTION_KS_INTERACTION_BEGIN);\n            broadcastIntent.setPackage(mContext.getPackageName());\n            mContext.sendBroadcast(broadcastIntent);\n            // Intent wrapper\n            Intent intent = new Intent(mContext, KeyStoreActivity.class);\n            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n            intent.putExtra(KeyStoreActivity.EXTRA_ALIAS, alias);\n            String ks = \"AM KeyStore\";","sourceCodeStart":481,"sourceCodeEnd":517,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/io/github/muntashirakon/AppManager/crypto/ks/KeyStoreManager.java#L481-L517","documentation":"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.","triggerScenarios":"Calling getAliasPassword(alias) (directly or via getKey) when sSharedPreferences.contains(getPrefAlias(alias)) is true but getString(prefAlias, null) returns null.","commonSituations":"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.","solutions":["Remove the corrupt pref entry and re-save the alias password so it is stored as a String.","Verify nothing writes the alias pref with a non-String type (contains() is true but getString returns null).","Wrap the read in a null check that falls back to prompting the user for the password instead of failing."],"exampleFix":"// before\nString encryptedPass = sSharedPreferences.getString(prefAlias, null);\nif (encryptedPass == null) {\n    throw new KeyStoreException(\"Stored pass is empty for alias \" + alias);\n}\n// after\nString encryptedPass = sSharedPreferences.getString(prefAlias, null);\nif (encryptedPass == null) {\n    sSharedPreferences.edit().remove(prefAlias).apply(); // clear corrupt entry\n    encryptedPass = promptAndEncryptPassword(alias);    // re-store as String\n    if (encryptedPass == null) throw new KeyStoreException(\"Stored pass is empty for alias \" + alias);\n}","handlingStrategy":"validation","validationCode":"// before calling getAliasPassword/getKey\nString prefAlias = getPrefAlias(alias);\nString stored = sSharedPreferences.getString(prefAlias, null);\nif (stored == null || stored.isEmpty()) {\n    // prompt user for the alias password and save it first\n    saveAliasPassword(alias, promptForPassword(alias));\n}","typeGuard":null,"tryCatchPattern":"// try\ntry {\n    char[] pass = keyStoreManager.getKey(alias);\n} catch (KeyStoreException e) {\n    if (e.getMessage().contains(\"Stored pass is empty\")) {\n        // corrupt/typed pref entry: clear and re-store\n        removeAliasPasswordPref(alias);\n        promptAndStoreAliasPassword(alias);\n    }\n}","preventionTips":["Only store alias passwords as String entries via the app's own encrypt-and-save API.","Check getString(...) directly rather than trusting contains() when reading prefs.","Serialize pref writes on a single thread to avoid partial reads/writes.","Never hand-edit or post-process the app's SharedPreferences XML."],"tags":["keystore","android","preferences","null-value"],"backgroundTag":"missing-config-value","analyzedSha":"0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5","analyzedAt":"2026-09-12T14:03:37.243Z","contentChangedAt":"2026-09-12T14:03:37.243Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}