hashicorp/packer · error

signer and key must match when both are set

Error message

signer and key must match when both are set

What it means

Configure-time validation in signingBackendConfig: when both `signer` and `key` are set they must be identical strings. Setting both to different references is ambiguous, so the backend config is rejected.

Solutions

  1. Make signer and key exactly the same value.
  2. Remove the redundant `key` field and keep only `signer`.
  3. Or remove `signer` and keep only `key` (key takes precedence as signerRef).
  4. Re-run packer validate on the template before building.

Example fix

// before
"signer": "file:///keys/release.pem",
"key": "file:///keys/old.pem"
// after
"signer": "file:///keys/release.pem"
Defensive patterns

Strategy: validation

Validate before calling

import (
	"encoding/json"
	"fmt"
)
type provCfg struct {
	Signer string `json:"signer"`
	Key    string `json:"key"`
}
func checkSignerKeyMatch(raw json.RawMessage) error {
	var c provCfg
	if err := json.Unmarshal(raw, &c); err != nil { return err }
	if c.Signer != "" && c.Key != "" && c.Signer != c.Key {
		return fmt.Errorf("signer and key must match when both are set")
	}
	return nil
}

Try / catch

if err := p.Configure(raws); err != nil {
	if strings.Contains(err.Error(), "signer and key must match") {
		return fmt.Errorf("template error: unify signer/key: %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: signingBackendConfig sees p.config.Signer non-empty and p.config.Key non-empty with signerRef != p.config.Key; raised during Configure or writeAttestation.

Common situations: User sets signer (e.g. file:///path/key.pem) and also an old `key` field left over from a template update with a different path; copy-paste of two example configs.

Related errors


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

Appendix: source

Thrown at post-processor/provenance/post-processor.go:382

	verifier, err := internalattestation.NewVerifier(ctx, backendConfig, signer)
	if err != nil {
		return nil, nil, err
	}

	return signer, verifier, nil
}

func (p *PostProcessor) signingBackendConfig() (internalattestation.BackendConfig, error) {
	mode := p.config.SigningMode
	if mode == "" {
		mode = internalattestation.SigningModeNone
	}

	signerRef := p.config.Signer
	if p.config.Key != "" {
		if signerRef != "" && signerRef != p.config.Key {
			return internalattestation.BackendConfig{}, fmt.Errorf("signer and key must match when both are set")
		}
		signerRef = p.config.Key
	}

	switch mode {
	case internalattestation.SigningModeNone:
		return internalattestation.BackendConfig{Mode: mode}, nil
	case internalattestation.SigningModeKey:
		if signerRef == "" {
			return internalattestation.BackendConfig{}, fmt.Errorf("signing_mode %q requires signer or key", mode)
		}
		return internalattestation.BackendConfig{
			Mode:        mode,
			SignerRef:   signerRef,
			VerifierRef: p.config.Verifier,
			Env:         p.currentEnv(),
		}, nil
	case internalattestation.SigningModeKMS:

View on GitHub (pinned to eb36e3c3e4)