{"record":{"id":"caf9c59d95397f8c","repo":"netbirdio/netbird","slug":"read-artifact-file-w","errorCode":null,"errorMessage":"read artifact file: %w","messagePattern":"read artifact file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/cmd/signer/artifactsign.go","lineNumber":141,"sourceCode":"\t\tprivKeyPEM = []byte(envKey)\n\t} else if privKeyFile != \"\" {\n\t\t// Fall back to file\n\t\tprivKeyPEM, err = os.ReadFile(privKeyFile)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"read private key file: %w\", err)\n\t\t}\n\t} else {\n\t\treturn fmt.Errorf(\"artifact private key must be provided via %s environment variable or --artifact-key-file flag\", envArtifactPrivateKey)\n\t}\n\n\tprivateKey, err := reposign.ParseArtifactKey(privKeyPEM)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse artifact private key: %w\", err)\n\t}\n\n\tartifactData, err := os.ReadFile(artifactFile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read artifact file: %w\", err)\n\t}\n\n\tsignature, err := reposign.SignData(privateKey, artifactData)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"sign artifact: %w\", err)\n\t}\n\n\tsigFile := artifactFile + \".sig\"\n\tif err := os.WriteFile(artifactFile+\".sig\", signature, 0o600); err != nil {\n\t\treturn fmt.Errorf(\"write signature file (%s): %w\", sigFile, err)\n\t}\n\n\tcmd.Printf(\"✅ Artifact signed successfully.\\n\")\n\tcmd.Printf(\"Signature file: %s\\n\", sigFile)\n\treturn nil\n}\n\nfunc handleVerifyArtifact(cmd *cobra.Command, pubKeyFile, artifactFile, signatureFile string) error {","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/cmd/signer/artifactsign.go#L123-L159","documentation":"os.ReadFile on the --artifact-file path failed during sign-artifact. The wrapped *fs.PathError carries the real cause: file does not exist, permission denied, or the path is a directory. Note the message omits the path (unlike the .sig write error), which slows down diagnosis.","triggerScenarios":"Running the signer from a different working directory with a relative path; signing a file the build step has not produced yet; passing a directory as --artifact-file; no read permission on the file.","commonSituations":"CI step ordering: sign-artifact runs before goreleaser/build finishes; path typo or wrong release directory; artifact owned by another user.","solutions":["Verify the path exists and is a regular file: ls -l <path>, and use an absolute path","Fix pipeline ordering so signing runs after the artifact is fully written","Check read permission on the file and traverse permission on parent directories","If diagnosing in scripts, reproduce with cat <path>"],"exampleFix":"// before\nartifactData, err := os.ReadFile(artifactFile)\nif err != nil {\n    return fmt.Errorf(\"read artifact file: %w\", err)\n}\n\n// after\nartifactData, err := os.ReadFile(artifactFile)\nif err != nil {\n    return fmt.Errorf(\"read artifact file %s: %w\", artifactFile, err)\n}","handlingStrategy":"validation","validationCode":"if info, err := os.Stat(artifactFile); err != nil || info.IsDir() || info.Size() == 0 {\n    log.Fatalf(\"artifact %s missing, empty, or not a file: %v\", artifactFile, err)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Make the signing step depend on the build artifact being produced and non-empty","Use absolute paths in release scripts","Fail the pipeline on empty build outputs before signing"],"tags":["go","cli","filesystem","release-signing"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}