shwenzhang/AndResGuard · error · ParameterException

Certificate file (--cert) must be specified

Error message

Certificate file (--cert) must be specified

What it means

This ParameterException is thrown by loadPrivateKeyAndCertsFromFiles when the certificate file path (--cert) was not provided. In file-based signing the X.509 certificate chain file is mandatory to embed the signer identity into the APK signature.

Solutions

  1. Pass the certificate: add --cert /path/to/cert.pem (or .crt/.der) matching the private key.
  2. If the certificate does not exist yet, generate it: 'openssl req -x509 -key private_key.pem -out cert.pem'.
  3. If you intended keystore signing, switch to --ks <keystore> where the cert chain lives inside the keystore.

Example fix

// before
apksigner sign --key private_key.pk8 --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 certFile = new File(certPath);
if (certPath == null || certPath.isEmpty() || !certFile.isFile()) {
  throw new IllegalArgumentException("--cert must point to an existing X.509 certificate file");
}

Try / catch

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

Prevention

When it happens

Trigger: Invoking file-based signing with --key supplied but no --cert; constructing SignerParams with keyFile set while certFile remains null.

Common situations: Scripts that pass the key path but forget the matching .pem/.crt; wrong assumption that the certificate is embedded in the .pk8 file (PKCS#8 keys contain no certificates); copying command lines from keystore-based examples.

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/e754f69f613be430. Report an issue: GitHub.

Appendix: source

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

                              + ". 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) {
          // Given that no password was specified, assume the blob is an unencrypted
          // private key blob
          keySpec = new PKCS8EncodedKeySpec(privateKeyBlob);

View on GitHub (pinned to e4df245d82)