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
- Pass the private key file: add --key /path/to/private_key.pk8 (or PEM) to the command.
- If you actually intended keystore-based signing, pass --ks <keystore> --ks-key-alias <alias> instead.
- 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
- Fail fast in build scripts: assert the key path variable is non-empty before invoking the signer.
- Decide explicitly between keystore mode (--ks) and file mode (--key/--cert); never mix partially.
- Keep signing commands in versioned scripts rather than ad-hoc shell history.
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
- Certificate file (--cert) must be specified
- At least one signer must be specified
- Failed to obtain key with alias
- entry " " does not contain certificates
- Failed to parse encrypted private key blob
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)