docker/cli · error

could not parse public key from file

Error message

could not parse public key from file: %s: %w

What it means

Returned by ingestPublicKeys() in `docker trust signer add` when the file was opened and read successfully but tufutils.ParsePEMPublicKey() cannot parse the bytes as a valid PEM-encoded public key. %s is the offending file path, %w is the parse error. This means the file is reachable and readable but is not a valid notary public key.

Solutions

  1. Export the public key in the correct PEM format expected by notary (use `docker trust key generate` to produce a compatible pair).
  2. Confirm you are passing the .pub file, not the private key.
  3. Validate the PEM structure manually (BEGIN/END PUBLIC KEY blocks, base64 intact).
  4. Regenerate the key pair with `docker trust key generate <name>` if the existing one is corrupt or wrong-format.

Example fix

// before
$ docker trust signer add alice reg.io/app --key alice-private.pem
Error: could not parse public key from file: alice-private.pem: ...

// after — generate a proper pair and pass the public key
$ docker trust key generate alice   # produces alice-*.pub and a private key
$ docker trust signer add alice reg.io/app --key alice-<id>.pub
Defensive patterns

Strategy: validation

Validate before calling

// Validate the PEM is a parseable public key before invoking signer add
import "encoding/pem"

func validatePEMPublicKey(path string) error {
    b, err := os.ReadFile(path)
    if err != nil { return err }
    block, _ := pem.Decode(b)
    if block == nil { return errors.New("not a PEM file") }
    if !strings.Contains(block.Type, "PUBLIC KEY") {
        return fmt.Errorf("PEM type %s is not a public key", block.Type)
    }
    return nil
}

Type guard

func isPEMPublicKey(b []byte) bool {
    block, _ := pem.Decode(b)
    if block == nil { return false }
    return strings.Contains(block.Type, "PUBLIC KEY")
}

Prevention

When it happens

Trigger: Passing `--key <file>` whose contents are not a PEM public key — e.g. a private key file, a PEM with an unsupported algorithm, a corrupted/truncated PEM, a non-PEM format (OpenSSH, JWK, DER), or a text file.

Common situations: Accidentally passing the private key (which is PEM but not a *public* key parseable here) instead of the public key; exporting the key in the wrong format; copy-paste truncating the PEM armor; key generated with an unsupported curve.

Related errors


AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07). Data as JSON: /api/errors/707efe8039c64e3f. Report an issue: GitHub.

Appendix: source

Thrown at cmd/docker-trust/trust/signer_add.go:134

	pubKeys := []data.PublicKey{}
	for _, pubKeyPath := range pubKeyPaths {
		// Read public key bytes from PEM file, limit to 1 KiB
		pubKeyFile, err := os.OpenFile(pubKeyPath, os.O_RDONLY, 0o666)
		if err != nil {
			return nil, fmt.Errorf("unable to read public key from file: %w", err)
		}
		defer pubKeyFile.Close()
		// limit to
		l := io.LimitReader(pubKeyFile, 1<<20)
		pubKeyBytes, err := io.ReadAll(l)
		if err != nil {
			return nil, fmt.Errorf("unable to read public key from file: %w", err)
		}

		// Parse PEM bytes into type PublicKey
		pubKey, err := tufutils.ParsePEMPublicKey(pubKeyBytes)
		if err != nil {
			return nil, fmt.Errorf("could not parse public key from file: %s: %w", pubKeyPath, err)
		}
		pubKeys = append(pubKeys, pubKey)
	}
	return pubKeys, nil
}

View on GitHub (pinned to 4f84911bfe)