netbirdio/netbird · error

no keys found in bundle

Error message

no keys found in bundle

What it means

Returned by parsePublicKeyBundle (client/internal/updater/reposign/key.go:94) when the loop over the bundle bytes produced zero keys, i.e. the input bundle was empty from the start (a non-empty bundle would have parsed at least one key or failed inside parsePublicKey). It is the fail-closed response to an artifact public-key file that contains no PEM key records.

Source

Thrown at client/internal/updater/reposign/key.go:94

// PublicKey wraps a public Key with its Metadata
type PublicKey struct {
	Key      ed25519.PublicKey
	Metadata KeyMetadata
}

func parsePublicKeyBundle(bundle []byte, typeTag string) ([]PublicKey, error) {
	var keys []PublicKey
	for len(bundle) > 0 {
		keyInfo, rest, err := parsePublicKey(bundle, typeTag)
		if err != nil {
			return nil, err
		}
		keys = append(keys, keyInfo)
		bundle = rest
	}
	if len(keys) == 0 {
		return nil, errors.New("no keys found in bundle")
	}
	return keys, nil
}

func parsePublicKey(data []byte, typeTag string) (PublicKey, []byte, error) {
	b, rest := pem.Decode(data)
	if b == nil {
		return PublicKey{}, nil, errors.New("failed to decode PEM data")
	}
	if b.Type != typeTag {
		return PublicKey{}, nil, fmt.Errorf("PEM type is %q, want %q", b.Type, typeTag)
	}

	// Unmarshal JSON-embedded format
	var pub PublicKey
	if err := json.Unmarshal(b.Bytes, &pub); err != nil {
		return PublicKey{}, nil, fmt.Errorf("failed to unmarshal public key: %w", err)
	}

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Re-download the artifact keys file and check it is non-empty before parsing.
  2. Validate the file size / first bytes (PEM header) before handing it to the verifier.
  3. If you produce the bundle: ensure the signing pipeline actually embedded at least one key.

Example fix

// before
keys, err := reposign.ParsePublicKeyBundle(data) // data may be empty

// after: guard emptiness early with context
if len(data) == 0 {
    return fmt.Errorf("artifact key bundle is empty (download truncated?)")
}
keys, err := reposign.ParsePublicKeyBundle(data)
Defensive patterns

Strategy: try-catch

Validate before calling

// Cheap pre-check: a usable bundle is non-empty and starts with a PEM block.
if len(bundle) == 0 {
    return fmt.Errorf("empty artifact key bundle")
}
if _, rest := pem.Decode(bundle); len(rest) == len(bundle) {
    return fmt.Errorf("bundle is not PEM-encoded")
}

Try / catch

keys, err := reposign.ParsePublicKeyBundle(bundle)
if err != nil {
    return fmt.Errorf("parse artifact key bundle (re-download it): %w", err)
}

Prevention

When it happens

Trigger: An empty (zero-length) public key bundle passed to parsePublicKeyBundle, typically from an empty or truncated download of the artifact keys file; a caller passing a nil/empty data slice after upstream verification steps.

Common situations: Update metadata points at an empty keys file; partial download or filesystem full during cache write; CI tooling generating an empty bundle during signing pipeline misconfiguration.

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/cbcbe7857443aac1. Report an issue: GitHub.