{"record":{"id":"e69ec3a064cf128f","repo":"netbirdio/netbird","slug":"write-private-key-file-s-w-e69ec3","errorCode":null,"errorMessage":"write private key file (%s): %w","messagePattern":"write private key file \\((.+?)\\): %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/cmd/signer/rootkey.go","lineNumber":63,"sourceCode":"\t\tpanic(err)\n\t}\n\tif err := createRootKeyCmd.MarkFlagRequired(\"pub-key-file\"); err != nil {\n\t\tpanic(err)\n\t}\n\tif err := createRootKeyCmd.MarkFlagRequired(\"expiration\"); err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc handleGenerateRootKey(cmd *cobra.Command, privKeyFile, pubKeyFile string, expiration time.Duration) error {\n\trk, privPEM, pubPEM, err := reposign.GenerateRootKey(expiration)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"generate root key: %w\", err)\n\t}\n\n\t// Write private key\n\tif err := os.WriteFile(privKeyFile, privPEM, 0o600); err != nil {\n\t\treturn fmt.Errorf(\"write private key file (%s): %w\", privKeyFile, err)\n\t}\n\n\t// Write public key\n\tif err := os.WriteFile(pubKeyFile, pubPEM, 0o600); err != nil {\n\t\treturn fmt.Errorf(\"write public key file (%s): %w\", pubKeyFile, err)\n\t}\n\n\tcmd.Printf(\"%s\\n\\n\", rk.String())\n\tcmd.Printf(\"✅ Root key pair generated successfully.\\n\")\n\treturn nil\n}\n","sourceCodeStart":45,"sourceCodeEnd":75,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/cmd/signer/rootkey.go#L45-L75","documentation":"Returned by the signer CLI's create-root-key command when os.WriteFile cannot persist the generated private key PEM to the path given with --priv-key-file (mode 0600). The error wraps the underlying *fs.PathError, so the real cause (ENOENT, EACCES, EROFS, ENOSPC) appears after the colon. The key pair is generated in memory first, so nothing has been written when this fires.","triggerScenarios":"Running `signer create-root-key --priv-key-file <path>` where <path> is in a directory that does not exist, is not writable by the current user, is on a read-only filesystem, or the disk is full. Also fires when the path points at a directory or an existing file that cannot be truncated/re-created (e.g., owned by root and run as non-root).","commonSituations":"Passing a bare filename while assuming the tool creates parent directories (it does not); running the tool as a normal user with a target under /etc or another root-owned dir; container or CI environments with read-only volumes; stale root-owned key files from a previous sudo run blocking the overwrite.","solutions":["Check that the parent directory of --priv-key-file exists and is writable by the current user (mkdir -p, chown/chmod as needed); the tool never creates directories.","If an old key file exists, verify you own it and that it is a regular file, then remove or overwrite it explicitly.","Re-run pointing at an absolute path in a writable location such as $HOME or a mounted workdir (e.g., --priv-key-file ./keys/root.priv).","If on a read-only root filesystem (container), mount an emptyDir/volume and write the key there."],"exampleFix":"# before\nsigner create-root-key --priv-key-file /etc/signer/root.priv --pub-key-file /etc/signer/root.pub --expiration 8760h\n# -> write private key file (/etc/signer/root.priv): open ...: permission denied\n\n# after\nmkdir -p ./keys && sudo chown $(id -u) ./keys\nsigner create-root-key --priv-key-file ./keys/root.priv --pub-key-file ./keys/root.pub --expiration 8760h","handlingStrategy":"validation","validationCode":"// before invoking the signer CLI, verify the target path is writable\nfunc canWrite(path string) bool {\n\tif fi, err := os.Stat(path); err == nil && !fi.Mode().IsRegular() {\n\t\treturn false // exists but is a dir/symlink target we cannot trust\n\t}\n\tdir := filepath.Dir(path)\n\tinfo, err := os.Stat(dir)\n\treturn err == nil && info.IsDir() && info.Mode().Perm()&0200 != 0\n}\n\n// usage: create dir + pre-check both key paths\nos.MkdirAll(filepath.Dir(privKeyFile), 0o700)\nif !canWrite(privKeyFile) { log.Fatal(\"private key path not writable\") }","typeGuard":null,"tryCatchPattern":"if err := cmd.Execute(); err != nil {\n\tvar pathErr *fs.PathError\n\tif errors.As(err, &pathErr) && errors.Is(pathErr.Err, fs.ErrPermission) {\n\t\t// surface a fix hint: target dir not writable by this uid\n\t}\n\t// EROFS/ENOSPC map to distinct host-level remediation\n}","preventionTips":["Pre-create the target directory with mkdir -p before running create-root-key; the tool never creates parents.","Run the signer as the user who owns the destination directory; avoid interleaving sudo and non-sudo runs that leave root-owned files behind.","Prefer a dedicated keys directory on a writable volume (workdir, mounted volume) over system paths in containers.","Treat a failed private-key write as abortive: delete any partial artifacts and re-run, never continue with half a key pair."],"tags":["go","cli","filesystem","permissions","signing"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}