{"record":{"id":"914072961b7cc296","repo":"henrygd/beszel","slug":"failed-to-read-key-file-w","errorCode":null,"errorMessage":"failed to read key file: %w","messagePattern":"failed to read key file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/cmd/agent/agent.go","lineNumber":132,"sourceCode":"\t// Try command line flag first\n\tif opts.key != \"\" {\n\t\treturn agent.ParseKeys(opts.key)\n\t}\n\n\t// Try environment variable\n\tif key, ok := utils.GetEnv(\"KEY\"); ok && key != \"\" {\n\t\treturn agent.ParseKeys(key)\n\t}\n\n\t// Try key file\n\tkeyFile, ok := utils.GetEnv(\"KEY_FILE\")\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"no key provided: must set -key flag, KEY env var, or KEY_FILE env var. Use 'beszel-agent help' for usage\")\n\t}\n\n\tpubKey, err := os.ReadFile(keyFile)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read key file: %w\", err)\n\t}\n\treturn agent.ParseKeys(string(pubKey))\n}\n\nfunc (opts *cmdOptions) getAddress() string {\n\treturn agent.GetAddress(opts.listen)\n}\n\n// handleFingerprint handles the \"fingerprint\" command with subcommands \"view\" and \"reset\".\nfunc handleFingerprint() {\n\tsubCmd := \"\"\n\tif len(os.Args) > 2 {\n\t\tsubCmd = os.Args[2]\n\t}\n\n\tswitch subCmd {\n\tcase \"\", \"view\":\n\t\tdataDir, _ := agent.GetDataDir()","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/henrygd/beszel/blob/b38fb7dafa60812cc22e6a84ce313e94f1ce0a32/internal/cmd/agent/agent.go#L114-L150","documentation":"When KEY_FILE is set, loadPublicKeys reads that file with os.ReadFile and parses its contents as SSH public keys. Any file-read failure (missing, permission denied, is-a-directory) is wrapped with %w so the agent fails fast with the underlying reason.","triggerScenarios":"KEY_FILE points to a nonexistent path, an unreadable file (permissions/ownership), a directory, or a secret mount not present at container start (Docker/K8s secret path mismatch, bind mount not propagated).","commonSituations":"Secret mounted at a different path than KEY_FILE; file owned by root with 600 perms while the agent runs unprivileged; path typo; SELinux/AppArmor blocking the read.","solutions":["Verify the path: run `ls -l \"$KEY_FILE\"` as the same user the agent runs as and fix typos.","Fix permissions/ownership so the agent user can read it (chmod 644, or 400 for secrets with correct owner).","In Docker/K8s, confirm the secret is mounted at exactly the KEY_FILE path before the agent starts.","If SELinux denies the read, restore labels (restorecon) or adjust policy."],"exampleFix":"# before\nKEY_FILE=/etc/beszel/key   # missing or root-only\n# after\nsudo install -m 0444 -o beszel /srv/secrets/beszel_pub /etc/beszel/key\nKEY_FILE=/etc/beszel/key","handlingStrategy":"validation","validationCode":"// pre-check readability before launching the agent\nif kf := os.Getenv(\"KEY_FILE\"); kf != \"\" {\n\tif f, err := os.Open(kf); err != nil {\n\t\tlog.Fatalf(\"KEY_FILE %q unreadable: %v\", kf, err)\n\t} else {\n\t\tf.Close()\n\t}\n}","typeGuard":null,"tryCatchPattern":"keys, err := loadPublicKeys(opts)\nif err != nil {\n\tif strings.HasPrefix(err.Error(), \"failed to read key file\") {\n\t\tlog.Printf(\"check KEY_FILE path, permissions, and secret mounts: %v\", err)\n\t}\n\tlog.Fatal(err)\n}","preventionTips":["Verify KEY_FILE path and permissions as the service user before deploy.","In K8s/Docker, mount secrets at the exact KEY_FILE path.","Use install -m 0444 (or 0400) with correct owner for key files.","Check SELinux/AppArmor denials when reads fail mysteriously."],"tags":["go","configuration","file-io","ssh","permissions"],"backgroundTag":"file-read-failure","analyzedSha":"b38fb7dafa60812cc22e6a84ce313e94f1ce0a32","analyzedAt":"2026-08-31T15:10:10.149Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}