{"record":{"id":"93e12a3c5a3e47ab","repo":"netbirdio/netbird","slug":"read-public-key-file-w","errorCode":null,"errorMessage":"read public key file: %w","messagePattern":"read public key file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/cmd/signer/artifactkey.go","lineNumber":150,"sourceCode":"\nfunc handleBundlePubKeys(cmd *cobra.Command, rootPrivKeyFile string, artifactPubKeyFiles []string, bundlePubKeysFile string) error {\n\tcmd.Println(\"📦 Bundling public keys into signed package...\")\n\n\tprivKeyPEM, err := os.ReadFile(rootPrivKeyFile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read root private key file: %w\", err)\n\t}\n\n\tprivateRootKey, err := reposign.ParseRootKey(privKeyPEM)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse private root key: %w\", err)\n\t}\n\n\tpublicKeys := make([]reposign.PublicKey, 0, len(artifactPubKeyFiles))\n\tfor _, pubFile := range artifactPubKeyFiles {\n\t\tpubPem, err := os.ReadFile(pubFile)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"read public key file: %w\", err)\n\t\t}\n\n\t\tpk, err := reposign.ParseArtifactPubKey(pubPem)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse artifact key: %w\", err)\n\t\t}\n\t\tpublicKeys = append(publicKeys, pk)\n\t}\n\n\tparsedKeys, signature, err := reposign.BundleArtifactKeys(privateRootKey, publicKeys)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"bundle artifact keys: %w\", err)\n\t}\n\n\tif err := os.WriteFile(bundlePubKeysFile, parsedKeys, 0o600); err != nil {\n\t\treturn fmt.Errorf(\"write public keys file (%s): %w\", bundlePubKeysFile, err)\n\t}\n","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/cmd/signer/artifactkey.go#L132-L168","documentation":"os.ReadFile failed on one of the --artifact-pub-key-file entries while looping over the list in handleBundlePubKeys. Note the message does not include the offending pubFile name, so correlate by position/count when multiple files are passed.","triggerScenarios":"Any entry in the repeated --artifact-pub-key-file list that does not exist or is unreadable; a trailing empty string from an unquoted, non-expanded shell variable; a directory passed instead of a file.","commonSituations":"Glob that matched nothing ('*.pub' unexpanded); typos in one of many paths; CI checkout missing one key artifact.","solutions":["Iterate the same file list and stat each path before rerunning to find the missing one","Quote globs and guard empty variables in the invoking script","Confirm each entry is a readable regular file"],"exampleFix":"// before (script)\nfor f in $PUB_KEYS; do ... done  # empty/typo entries slip through silently\n// after\nfor f in $PUB_KEYS; do [ -r \"$f\" ] || { echo \"missing: $f\"; exit 1; }; done","handlingStrategy":"validation","validationCode":"for _, f := range artifactPubKeyFiles {\n    info, err := os.Stat(f)\n    if err != nil || info.IsDir() {\n        log.Fatalf(\"artifact public key not readable: %s\", f)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Check every path in the repeated flag list before invoking the CLI","Quote globs in shell; bail out when a glob matches nothing","Assert the count of inputs matches the expected key count in CI"],"tags":["cli","file-io","signing","go"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}