shwenzhang/AndResGuard · error · ParameterException

Private key file (--key) must be specified

Error message

Private key file (--key) must be specified

What it means

This ParameterException is thrown by loadPrivateKeyAndCertsFromFiles when the raw private key path (--key) was not provided. This code path runs when signing is configured to read the key from PEM/PKCS#8 files instead of a keystore, and a null keyFile makes signing impossible.

Solutions

  1. Pass the private key file: add --key /path/to/private_key.pk8 (or PEM) to the command.
  2. If you actually intended keystore-based signing, pass --ks <keystore> --ks-key-alias <alias> instead.
  3. Check the wrapper script/env for an unset KEY variable (e.g. "$KEY_PATH" expanding to nothing).

Example fix

// before
apksigner sign --cert cert.pem --out signed.apk unsigned.apk
// after
apksigner sign --key private_key.pk8 --cert cert.pem --out signed.apk unsigned.apk
Defensive patterns

Strategy: validation

Validate before calling

File keyFile = new File(keyPath);
if (keyPath == null || keyPath.isEmpty() || !keyFile.isFile()) {
  throw new IllegalArgumentException("--key must point to an existing private key file (PKCS#8/PEM)");
}

Try / catch

try {
  signerParams.loadPrivateKeyAndCerts(passwordRetriever);
} catch (ParameterException e) {
  if (e.getMessage() != null && e.getMessage().contains("--key) must be specified")) {
    throw new IllegalArgumentException("Provide --key <private key file> for file-based signing, or --ks for keystore signing", e);
  } throw e;
}

Prevention

When it happens

Trigger: Invoking the signer with file-based signing (no --ks) but omitting the --key argument; programmatically constructing SignerParams with certFile set but keyFile left null.

Common situations: Switching a build from keystore-based to file-based signing and forgetting --key; shell scripts where a KEY_PATH variable is empty; docs examples showing only --cert.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of shwenzhang/AndResGuard@e4df245d82 (2026-09-12). Data as JSON: /api/errors/280219c0232c6ea4. Report an issue: GitHub.

Appendix: source

Thrown at AndResGuard-core/src/main/java/apksigner/ApkSignerTool.java:779

                              + keyAlias
                              + "\" from "
                              + keystoreFile
                              + ". Wrong password?", e);
      }
      this.privateKey = key;
      Certificate[] certChain = ks.getCertificateChain(keyAlias);
      if ((certChain == null) || (certChain.length == 0)) {
        throw new ParameterException(keystoreFile + " entry \"" + keyAlias + "\" does not contain certificates");
      }
      this.certs = new ArrayList<>(certChain.length);
      for (Certificate cert : certChain) {
        this.certs.add((X509Certificate) cert);
      }
    }

    private void loadPrivateKeyAndCertsFromFiles(PasswordRetriever passwordRetriver) throws Exception {
      if (keyFile == null) {
        throw new ParameterException("Private key file (--key) must be specified");
      }
      if (certFile == null) {
        throw new ParameterException("Certificate file (--cert) must be specified");
      }
      byte[] privateKeyBlob = readFully(new File(keyFile));

      PKCS8EncodedKeySpec keySpec;
      // Potentially encrypted key blob
      try {
        EncryptedPrivateKeyInfo encryptedPrivateKeyInfo = new EncryptedPrivateKeyInfo(privateKeyBlob);

        // The blob is indeed an encrypted private key blob
        String passwordSpec = (keyPasswordSpec != null) ? keyPasswordSpec : PasswordRetriever.SPEC_STDIN;
        List<char[]> keyPasswords = passwordRetriver.getPasswords(passwordSpec, "Private key password for " + name);
        keySpec = decryptPkcs8EncodedKey(encryptedPrivateKeyInfo, keyPasswords);
      } catch (IOException e) {
        // The blob is not an encrypted private key blob
        if (keyPasswordSpec == null) {

View on GitHub (pinned to e4df245d82)