{"record":{"id":"72450f4ae268600e","repo":"hashicorp/packer","slug":"read-signer-q-w","errorCode":null,"errorMessage":"read signer %q: %w","messagePattern":"read signer %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/attestation/sign_key.go","lineNumber":137,"sourceCode":"}\n\nfunc LoadPEMVerifierBytes(contents []byte) (*pemVerifier, error) {\n\tpublicKey, rawVerifier, err := loadPEMPublicKey(contents)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &pemVerifier{\n\t\tpublicKey: publicKey,\n\t\tkeyID:     sha256Hex(rawVerifier),\n\t}, nil\n\n}\n\nfunc loadPEMSigner(path string) (crypto.Signer, *pemVerifier, error) {\n\tcontents, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"read signer %q: %w\", path, err)\n\t}\n\n\tblock, _ := pem.Decode(contents)\n\tif block == nil {\n\t\treturn nil, nil, fmt.Errorf(\"decode signer %q: no PEM block found\", path)\n\t}\n\n\tvar signer crypto.Signer\n\tif key, err := x509.ParsePKCS8PrivateKey(block.Bytes); err == nil {\n\t\tvar ok bool\n\t\tsigner, ok = key.(crypto.Signer)\n\t\tif !ok {\n\t\t\treturn nil, nil, fmt.Errorf(\"signer %q does not implement crypto.Signer\", path)\n\t\t}\n\t} else if key, err := x509.ParsePKCS1PrivateKey(block.Bytes); err == nil {\n\t\tsigner = key\n\t} else if key, err := x509.ParseECPrivateKey(block.Bytes); err == nil {\n\t\tsigner = key","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/internal/attestation/sign_key.go#L119-L155","documentation":"loadPEMSigner (reached via newPEMSigner) could not read the signer's private-key file because os.ReadFile failed. The OS error is wrapped with %w so the concrete reason (missing file, permission denied, is-a-directory) is preserved. This happens before any PEM parsing is attempted.","triggerScenarios":"Calling newPEMSigner(path) where the private-key path does not exist, is unreadable by the process user, or is a directory/special file.","commonSituations":"Wrong path in signing config; key never mounted into the container; permissions tightened to 0600 under a different service account; secret-manager sync failed so the key file is absent at startup.","solutions":["Check the path exists with os.Stat and correct any typo in the signer key path.","Fix permissions so the process user can read the private key (e.g. chmod 600 key.pem + correct owner).","If the key is mounted from a secret manager, verify the mount/sync completed before calling newPEMSigner.","Inspect the wrapped OS error (errors.Is(err, fs.ErrNotExist) / fs.ErrPermission) for the exact cause."],"exampleFix":"// before\nsigner, verifier, err := attestation.NewSigner(\"signing-key.pem\") // ENOENT\n// after\nsigner, verifier, err := attestation.NewSigner(\"/etc/packer/keys/signing-key.pem\") // absolute, verified path","handlingStrategy":"validation","validationCode":"info, err := os.Stat(keyPath)\nif err != nil {\n\treturn fmt.Errorf(\"signer key %q unavailable: %w\", keyPath, err)\n}\nif info.Mode().Perm()&0o077 != 0 {\n\treturn fmt.Errorf(\"signer key %q too permissive: %v\", keyPath, info.Mode().Perm())\n}","typeGuard":null,"tryCatchPattern":"signer, verifier, err := attestation.NewSigner(keyPath)\nif err != nil {\n\tif errors.Is(err, fs.ErrNotExist) {\n\t\treturn fmt.Errorf(\"signing key not found: %s\", keyPath)\n\t}\n\tif errors.Is(err, fs.ErrPermission) {\n\t\treturn fmt.Errorf(\"signing key %s: permission denied\", keyPath)\n\t}\n\treturn err\n}","preventionTips":["Keep private-key paths in one config location with absolute paths.","Set keys to 0600 owned by the service user; verify at deployment.","Fail fast at startup by loading the signer once, not lazily on first signature.","For containerized runs, assert secret mounts exist in the entrypoint script."],"tags":["go","file-io","pem","signing"],"backgroundTag":"file-not-found","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"}