shwenzhang/AndResGuard · error · ParameterException
contains multiple key entries. --ks-key-alias option must…
Error message
<keystoreFile> contains multiple key entries. --ks-key-alias option must be used to specify which entry to use.
What it means
apksigner's keystore loader iterates all aliases in the keystore and picks the first key entry as the signing key. When a second key entry is found while --ks-key-alias was not given, the ambiguity is unrecoverable, so a ParameterException is thrown telling the user to explicitly name which alias to sign with.
Solutions
- Pass the desired alias explicitly: apksigner sign --ks my.keystore --ks-key-alias <alias> ...
- List the keystore entries first with keytool -list -keystore my.keystore to see available aliases and pick the right one.
- If the extra entries are obsolete, delete them or create a keystore containing only the signing key.
- In calling code, resolve/verify the alias before invoking (KeyStore.aliases() + isKeyEntry) and pass it to the signer.
Example fix
// before apksigner sign --ks release.keystore --ks-key-pass ... --out app.apk app-unsigned.apk // after apksigner sign --ks release.keystore --ks-key-alias release --ks-key-pass ... --out app.apk app-unsigned.apk
Defensive patterns
Strategy: validation
Validate before calling
KeyStore ks = KeyStore.getInstance("PKCS12");
try (FileInputStream in = new FileInputStream(ksFile)) { ks.load(in, storePassword); }
java.util.List<String> keyAliases = new java.util.ArrayList<>();
java.util.Enumeration<String> a = ks.aliases();
while (a.hasMoreElements()) { String al = a.nextElement(); if (ks.isKeyEntry(al)) keyAliases.add(al); }
if (keyAliases.size() > 1 && keyAliasArg == null)
throw new IllegalArgumentException("Keystore has multiple key entries; pass --ks-key-alias. Found: " + keyAliases); Prevention
- Always pass --ks-key-alias in build scripts so behavior is explicit
- Run keytool -list -keystore ... in CI before signing to confirm the alias exists
- Keep one signing key per keystore file
- Pin the exact keystore file + alias pair in Gradle/CI config
When it happens
Trigger: Running apksigner sign (or loadPrivateKeyAndCerts via loadPrivateKeyAndCertsFromKeyStore) with a --ks file that contains two or more KeyEntry aliases (multiple private keys) while omitting the --ks-key-alias option.
Common situations: Developers reuse a debug keystore that accumulated several generated keys over time; CI pipelines migrated from a single-key keystore to a multi-key one; teams share one keystore holding release and debug signing keys; Android Studio-generated keystores later merged with another keystore.
Understand the failure class
Background: "Must pass :limit option" / "Missing required option" — required option errors explained — this error's family across 41 libraries.
Related errors
- does not contain key entries
- entry " " does not contain a key
- entry " " does not contain a private key. It contains a key…
- Missing APK
- Unexpected parameter(s) after APK (<params[1]>)
AI-assisted analysis of shwenzhang/AndResGuard@e4df245d82 (2026-09-12).
Data as JSON: /api/errors/e33169b4c2d2008a.
Report an issue: GitHub.
Appendix: source
Thrown at AndResGuard-core/src/main/java/apksigner/ApkSignerTool.java:705
keystorePasswords = passwordRetriever.getPasswords(keystorePasswordSpec, "Keystore password for " + name);
loadKeyStoreFromFile(ks, keystoreFile, keystorePasswords);
}
// 3. Load the PrivateKey and cert chain from KeyStore
String keyAlias = null;
PrivateKey key = null;
try {
if (keystoreKeyAlias == null) {
// Private key entry alias not specified. Find the key entry contained in this
// KeyStore. If the KeyStore contains multiple key entries, return an error.
Enumeration<String> aliases = ks.aliases();
if (aliases != null) {
while (aliases.hasMoreElements()) {
String entryAlias = aliases.nextElement();
if (ks.isKeyEntry(entryAlias)) {
keyAlias = entryAlias;
if (keystoreKeyAlias != null) {
throw new ParameterException(keystoreFile
+ " contains multiple key entries"
+ ". --ks-key-alias option must be used to specify"
+ " which entry to use.");
}
keystoreKeyAlias = keyAlias;
}
}
}
if (keystoreKeyAlias == null) {
throw new ParameterException(keystoreFile + " does not contain key entries");
}
}
// Private key entry alias known. Load that entry's private key.
keyAlias = keystoreKeyAlias;
if (!ks.isKeyEntry(keyAlias)) {
throw new ParameterException(keystoreFile + " entry \"" + keyAlias + "\" does not contain a key");
}View on GitHub (pinned to e4df245d82)