{"record":{"id":"ae295a2c4c9fcb4d","repo":"hashicorp/packer","slug":"signer-and-key-must-match-when-both-are-set","errorCode":null,"errorMessage":"signer and key must match when both are set","messagePattern":"signer and key must match when both are set","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"post-processor/provenance/post-processor.go","lineNumber":382,"sourceCode":"\n\tverifier, err := internalattestation.NewVerifier(ctx, backendConfig, signer)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn signer, verifier, nil\n}\n\nfunc (p *PostProcessor) signingBackendConfig() (internalattestation.BackendConfig, error) {\n\tmode := p.config.SigningMode\n\tif mode == \"\" {\n\t\tmode = internalattestation.SigningModeNone\n\t}\n\n\tsignerRef := p.config.Signer\n\tif p.config.Key != \"\" {\n\t\tif signerRef != \"\" && signerRef != p.config.Key {\n\t\t\treturn internalattestation.BackendConfig{}, fmt.Errorf(\"signer and key must match when both are set\")\n\t\t}\n\t\tsignerRef = p.config.Key\n\t}\n\n\tswitch mode {\n\tcase internalattestation.SigningModeNone:\n\t\treturn internalattestation.BackendConfig{Mode: mode}, nil\n\tcase internalattestation.SigningModeKey:\n\t\tif signerRef == \"\" {\n\t\t\treturn internalattestation.BackendConfig{}, fmt.Errorf(\"signing_mode %q requires signer or key\", mode)\n\t\t}\n\t\treturn internalattestation.BackendConfig{\n\t\t\tMode:        mode,\n\t\t\tSignerRef:   signerRef,\n\t\t\tVerifierRef: p.config.Verifier,\n\t\t\tEnv:         p.currentEnv(),\n\t\t}, nil\n\tcase internalattestation.SigningModeKMS:","sourceCodeStart":364,"sourceCodeEnd":400,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/post-processor/provenance/post-processor.go#L364-L400","documentation":"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.","triggerScenarios":"signingBackendConfig sees p.config.Signer non-empty and p.config.Key non-empty with signerRef != p.config.Key; raised during Configure or writeAttestation.","commonSituations":"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.","solutions":["Make signer and key exactly the same value.","Remove the redundant `key` field and keep only `signer`.","Or remove `signer` and keep only `key` (key takes precedence as signerRef).","Re-run packer validate on the template before building."],"exampleFix":"// before\n\"signer\": \"file:///keys/release.pem\",\n\"key\": \"file:///keys/old.pem\"\n// after\n\"signer\": \"file:///keys/release.pem\"","handlingStrategy":"validation","validationCode":"import (\n\t\"encoding/json\"\n\t\"fmt\"\n)\ntype provCfg struct {\n\tSigner string `json:\"signer\"`\n\tKey    string `json:\"key\"`\n}\nfunc checkSignerKeyMatch(raw json.RawMessage) error {\n\tvar c provCfg\n\tif err := json.Unmarshal(raw, &c); err != nil { return err }\n\tif c.Signer != \"\" && c.Key != \"\" && c.Signer != c.Key {\n\t\treturn fmt.Errorf(\"signer and key must match when both are set\")\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"if err := p.Configure(raws); err != nil {\n\tif strings.Contains(err.Error(), \"signer and key must match\") {\n\t\treturn fmt.Errorf(\"template error: unify signer/key: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Keep only one of signer/key in templates.","Grep templates for duplicated signing fields when migrating configs.","Run packer validate before every build."],"tags":["configuration","validation","signing"],"backgroundTag":"conflicting-config-fields","analyzedSha":"eb36e3c3e48a036f3e8cc94087636ee72e1303c9","analyzedAt":"2026-09-05T13:20:43.127Z","contentChangedAt":"2026-09-05T13:20:43.127Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}