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

  1. Pass the desired alias explicitly: apksigner sign --ks my.keystore --ks-key-alias <alias> ...
  2. List the keystore entries first with keytool -list -keystore my.keystore to see available aliases and pick the right one.
  3. If the extra entries are obsolete, delete them or create a keystore containing only the signing key.
  4. 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

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


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)