hashicorp/packer · error

decode signer %q: no PEM block found

Error message

decode signer %q: no PEM block found

What it means

loadPEMSigner read the file but pem.Decode returned nil, meaning the contents contain no valid PEM block at all. PEM requires the '-----BEGIN ...-----'/'-----END ...-----' ASCII armor; raw DER bytes, JSON, or an empty file all fail here. The message is static (not wrapped), so the path is included for identification only.

Source

Thrown at internal/attestation/sign_key.go:142

		return nil, err
	}

	return &pemVerifier{
		publicKey: publicKey,
		keyID:     sha256Hex(rawVerifier),
	}, nil

}

func loadPEMSigner(path string) (crypto.Signer, *pemVerifier, error) {
	contents, err := os.ReadFile(path)
	if err != nil {
		return nil, nil, fmt.Errorf("read signer %q: %w", path, err)
	}

	block, _ := pem.Decode(contents)
	if block == nil {
		return nil, nil, fmt.Errorf("decode signer %q: no PEM block found", path)
	}

	var signer crypto.Signer
	if key, err := x509.ParsePKCS8PrivateKey(block.Bytes); err == nil {
		var ok bool
		signer, ok = key.(crypto.Signer)
		if !ok {
			return nil, nil, fmt.Errorf("signer %q does not implement crypto.Signer", path)
		}
	} else if key, err := x509.ParsePKCS1PrivateKey(block.Bytes); err == nil {
		signer = key
	} else if key, err := x509.ParseECPrivateKey(block.Bytes); err == nil {
		signer = key
	} else {
		return nil, nil, fmt.Errorf("unsupported private key in signer %q", path)
	}

	publicKeyPEM, err := marshalPublicKeyPEM(signer.Public())

View on GitHub (pinned to eb36e3c3e4)

Solutions

  1. Verify the file literally starts with '-----BEGIN' (head -1 key.pem); convert raw DER with 'openssl pkcs8 -inform DER -in key.der -out key.pem'.
  2. Re-export or re-download the key ensuring PEM (base64 armor) output.
  3. Check the file is not empty and was not truncated (compare byte size with the source).
  4. Call pem.Decode yourself in a pre-check to validate the file before invoking the signer.

Example fix

// before
$ openssl pkcs8 -topk8 -in key.pem -outform DER -out key.der  // no armor
signer, _, err := attestation.NewSigner("key.der") // no PEM block found
// after
$ openssl pkcs8 -topk8 -in key.pem -out key.pem.new // PEM armor kept
signer, _, err := attestation.NewSigner("key.pem.new")
Defensive patterns

Strategy: validation

Validate before calling

raw, err := os.ReadFile(keyPath)
if err != nil {
	return err
}
block, _ := pem.Decode(raw)
if block == nil {
	return fmt.Errorf("%s: no PEM armor; expected -----BEGIN ... PRIVATE KEY-----", keyPath)
}

Type guard

func isPEM(b []byte) bool {
	block, _ := pem.Decode(b)
	return block != nil
}

Try / catch

signer, verifier, err := attestation.NewSigner(keyPath)
if err != nil && strings.Contains(err.Error(), "no PEM block found") {
	return fmt.Errorf("%s must be PEM-encoded; convert DER with: openssl pkcs8 -inform DER -in key.der -out key.pem", keyPath)
}

Prevention

When it happens

Trigger: Calling newPEMSigner(path) with a file containing raw DER-encoded key bytes, base64 without armor lines, an empty file, or text where the BEGIN line is malformed (e.g. wrong number of dashes or extra leading bytes before the header).

Common situations: Exported key with 'openssl pkcs8 -topk8 -outform DER'; base64 blob pasted into a file without armor; downloading a key through a tool that stripped newlines; truncated/corrupted file after a failed transfer.

Related errors


AI-assisted analysis of hashicorp/packer@eb36e3c3e4 (2026-09-05). Data as JSON: /api/errors/1ce27d7187fac6c6. Report an issue: GitHub.