{"record":{"id":"d7f80462100017e0","repo":"shwenzhang/AndResGuard","slug":"keystorefile-entry-keyalias-does-not-contain-certificates","errorCode":null,"errorMessage":"<keystoreFile> entry \"<keyAlias>\" does not contain certificates","messagePattern":"<keystoreFile> entry \"<keyAlias>\" does not contain certificates","errorType":"validation","errorClass":"ParameterException","httpStatus":null,"severity":"error","filePath":"AndResGuard-core/src/main/java/apksigner/ApkSignerTool.java","lineNumber":769,"sourceCode":"          throw new ParameterException(keystoreFile\n                                       + \" entry \\\"\"\n                                       + keyAlias\n                                       + \"\\\" does not contain a private\"\n                                       + \" key. It contains a key of algorithm: \"\n                                       + entryKey.getAlgorithm());\n        }\n        key = (PrivateKey) entryKey;\n      } catch (UnrecoverableKeyException e) {\n        throw new IOException(\"Failed to obtain key with alias \\\"\"\n                              + keyAlias\n                              + \"\\\" from \"\n                              + keystoreFile\n                              + \". Wrong password?\", e);\n      }\n      this.privateKey = key;\n      Certificate[] certChain = ks.getCertificateChain(keyAlias);\n      if ((certChain == null) || (certChain.length == 0)) {\n        throw new ParameterException(keystoreFile + \" entry \\\"\" + keyAlias + \"\\\" does not contain certificates\");\n      }\n      this.certs = new ArrayList<>(certChain.length);\n      for (Certificate cert : certChain) {\n        this.certs.add((X509Certificate) cert);\n      }\n    }\n\n    private void loadPrivateKeyAndCertsFromFiles(PasswordRetriever passwordRetriver) throws Exception {\n      if (keyFile == null) {\n        throw new ParameterException(\"Private key file (--key) must be specified\");\n      }\n      if (certFile == null) {\n        throw new ParameterException(\"Certificate file (--cert) must be specified\");\n      }\n      byte[] privateKeyBlob = readFully(new File(keyFile));\n\n      PKCS8EncodedKeySpec keySpec;\n      // Potentially encrypted key blob","sourceCodeStart":751,"sourceCodeEnd":787,"githubUrl":"https://github.com/shwenzhang/AndResGuard/blob/e4df245d82f27d9a2d0dd108260a3510cbaba849/AndResGuard-core/src/main/java/apksigner/ApkSignerTool.java#L751-L787","documentation":"This ParameterException is thrown after the private key is recovered successfully when KeyStore.getCertificateChain(keyAlias) returns null or an empty array. A valid signing key entry must carry the certificate chain needed to build the APK signature; an alias without certificates cannot be used to sign.","triggerScenarios":"loadPrivateKeyAndCertsFromKeyStore resolves the private key for --ks-key-alias, but the keystore entry under that alias holds only a raw key (e.g. a key imported without its certificate) or the alias actually points to a trusted-certificate-only entry with no private key chain.","commonSituations":"Importing a bare .key/PKCS#8 file into a keystore without 'keytool -importcert' for its certificate; aliases pointing to TrustedCertificateEntry rather than PrivateKeyEntry; corrupted or partially built keystores in CI caches.","solutions":["Inspect the entry with 'keytool -list -v -keystore <keystoreFile> -alias <keyAlias>' and confirm it is a PrivateKeyEntry with a certificate chain.","Re-generate the key with its certificate: 'keytool -genkeypair -alias <keyAlias> ...' so the entry includes the chain.","If the key was imported without a cert, create/import the matching certificate: 'keytool -importcert -alias <keyAlias> -file cert.pem'.","Double-check --ks-key-alias spelling; a similar alias may exist without certificates."],"exampleFix":"// before: bare key import\nkeytool -importkeystore ... // key entry without certificate\n// after\ncerttool --self-sign && keytool -importcert -alias release -file release.crt -keystore release.jks","handlingStrategy":"validation","validationCode":"KeyStore ks = KeyStore.getInstance(new File(ksFile), ksPassword.toCharArray());\njava.security.cert.Certificate[] chain = ks.getCertificateChain(alias);\nKey key = ks.getKey(alias, keyPass.toCharArray());\nif (key instanceof PrivateKey && (chain == null || chain.length == 0)) {\n  throw new IllegalStateException(\"Entry \" + alias + \" has a private key but no certificate chain; re-export with its cert.\");\n}","typeGuard":"boolean isSignableEntry(KeyStore ks, String alias, char[] keyPass) throws Exception {\n  java.security.cert.Certificate[] c = ks.getCertificateChain(alias);\n  return ks.getKey(alias, keyPass) instanceof PrivateKey && c != null && c.length > 0;\n}","tryCatchPattern":"try {\n  signerParams.loadPrivateKeyAndCerts(passwordRetriever);\n} catch (ParameterException e) {\n  if (e.getMessage() != null && e.getMessage().endsWith(\"does not contain certificates\")) {\n    throw new IllegalStateException(\"Keystore entry lacks certificate chain - re-create with keytool -genkeypair\", e);\n  } throw e;\n}","preventionTips":["Always create signing keys with keytool -genkeypair so the certificate chain is embedded in the entry.","Never import a bare private key into a keystore without its matching certificate.","Run 'keytool -list -v' in CI as a pre-flight check for PrivateKeyEntry + chain length."],"tags":["keystore","signing","certificate-chain","android"],"backgroundTag":"missing-certificate-chain","analyzedSha":"e4df245d82f27d9a2d0dd108260a3510cbaba849","analyzedAt":"2026-09-12T17:49:07.798Z","contentChangedAt":"2026-09-12T17:49:07.798Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}