theonedev/onedev · error · ExplicitException

No public key found

Error message

No public key found

What it means

GpgUtils.parse reads an armored/binary keyring and iterates all key rings collecting public keys. If the ring contains no public keys at all, it throws ExplicitException("No public key found"). ExplicitException means this is an expected, user-facing validation error, not a bug.

Source

Thrown at server-core/src/main/java/io/onedev/server/util/GpgUtils.java:55

import io.onedev.commons.utils.ExplicitException;
import io.onedev.commons.utils.StringUtils;

public class GpgUtils {

	public static List<PGPPublicKey> parse(String publicKeyString) {
		try (InputStream in = PGPUtil
				.getDecoderStream(new ByteArrayInputStream(publicKeyString.getBytes(StandardCharsets.UTF_8)))) {
			List<PGPPublicKey> publicKeys = new ArrayList<>();
			JcaPGPPublicKeyRingCollection ringCollection = new JcaPGPPublicKeyRingCollection(in);
			Iterator<PGPPublicKeyRing> itRing = ringCollection.getKeyRings();
			while (itRing.hasNext()) {
				Iterator<PGPPublicKey> itKey = itRing.next().getPublicKeys();
				while (itKey.hasNext()) 
					publicKeys.add(itKey.next());
			}
			if (publicKeys.isEmpty())
				throw new ExplicitException("No public key found");
			return publicKeys;
		} catch (IOException | PGPException e) {
			throw new RuntimeException(e);
		}
	}

	public static List<String> getEmailAddresses(PGPPublicKey publicKey) {
		List<String> emailAddresses = new ArrayList<>();
		Iterator<String> it = publicKey.getUserIDs();
		while (it.hasNext())
			emailAddresses.add(getEmailAddress(it.next()));
		return emailAddresses;
	}
	
	public static String getEmailAddress(String userId) {
		return StringUtils.substringBefore(StringUtils.substringAfter(userId, "<"), ">");
	}

View on GitHub (pinned to d44925c47c)

Solutions

  1. Export the public key properly: gpg --armor --export <key-id> (or --export-options export-public) and paste that.
  2. Verify the content with gpg --show-keys (or gpg --list-packets) before uploading; ensure it starts with -----BEGIN PGP PUBLIC KEY BLOCK-----.
  3. If the file is a secret keyring, derive the public key: gpg --armor --export <fingerprint>.
  4. Check the file is not empty and was fully copied (no truncation).

Example fix

// before: pasting secret key
-----BEGIN PGP PRIVATE KEY BLOCK----- ... // throws 'No public key found'
// after
gpg --armor --export ABCD1234 > pubkey.asc  # paste contents of pubkey.asc
Defensive patterns

Strategy: validation

Validate before calling

String content = keyValue.trim();
if (content.isEmpty() || !content.contains("BEGIN PGP PUBLIC KEY BLOCK")) {
    throw new IllegalArgumentException("Please provide an armored public key");
}

Try / catch

try {
    List<PGPPublicKey> keys = GpgUtils.parse(in);
} catch (ExplicitException e) {
    // show user-facing message: 'the provided key material contains no public key'
}

Prevention

When it happens

Trigger: Parsing a GPG key block that contains only secret keys or subkey packets the loader cannot expose, an empty file/stream, or an armored blob whose packets decode but yield no PGPPublicKey entries.

Common situations: Users pasting a private key where a public key is expected (e.g. verifiers/commit signing settings), pasting text that isn't a public key (passwords, SSH keys), or truncated/corrupted key exports.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06). Data as JSON: /api/errors/7bf1adb3ad129da7. Report an issue: GitHub.