{"record":{"id":"bd499212693a3d42","repo":"gastownhall/beads","slug":"failed-to-stat-config-yaml-w","errorCode":null,"errorMessage":"failed to stat config.yaml: %w","messagePattern":"failed to stat config\\.yaml: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/yaml_config.go","lineNumber":296,"sourceCode":"\treturn setYamlConfigAtPath(configPath, key, value)\n}\n\n// SetYamlConfigInDir sets a configuration value in the config.yaml located in\n// the provided beadsDir, bypassing CWD/worktree discovery. Use this when the\n// caller has already resolved the authoritative workspace and needs to avoid\n// local worktree stubs shadowing the real shared config location.\nfunc SetYamlConfigInDir(beadsDir, key, value string) error {\n\t// Validate specific keys (GH#995)\n\tif err := validateYamlConfigValue(key, value); err != nil {\n\t\treturn err\n\t}\n\n\tconfigPath := filepath.Join(beadsDir, \"config.yaml\")\n\tif _, err := os.Stat(configPath); err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\treturn fmt.Errorf(\"no config.yaml found in %s (run 'bd init' first)\", beadsDir)\n\t\t}\n\t\treturn fmt.Errorf(\"failed to stat config.yaml: %w\", err)\n\t}\n\n\treturn setYamlConfigAtPath(configPath, key, value)\n}\n\nvar userGlobalKeyPrefixes = []string{\"metrics.\"}\n\n// userGlobalExactKeys are per-MACHINE settings that must never be written to\n// the project .beads/config.yaml, which is a git-TRACKED file (see\n// cmd/bd/doctor/gitignore.go: nothing in .beads/.gitignore excludes it). A\n// committed value propagates one machine's answer to every clone that pulls\n// it, which for these keys is worse than having no value at all.\n//\n// node_id is the exemplar: it names the beads STORE that grants leases here,\n// and the reclaim guard (issueops.ReclaimExpiredLeasesInTx) compares it\n// against each lease's granted_node. Commit \"node_id: mini\" and every replica\n// reads \"mini\", so every comparison matches and the guard is simultaneously\n// fully ARMED and fully INERT — laptop reaps mini's leases exactly as if they","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/config/yaml_config.go#L278-L314","documentation":"SetYamlConfigInDir stats <beadsDir>/config.yaml before writing; when Stat fails for any reason other than not-exists (permission denied, path is a directory, I/O error), the raw error is wrapped as 'failed to stat config.yaml'. It distinguishes real I/O problems from the friendly not-found message.","triggerScenarios":"os.Stat on the config.yaml path fails with a non-ENOENT error: the path exists but is a directory named config.yaml, the .beads directory is unreadable (permissions), or a filesystem/I/O error occurs (EIO, stale NFS mount).","commonSituations":"config.yaml accidentally replaced by a directory; .beads dir with restrictive ownership after sudo/copy; read-only or disconnected network mounts.","solutions":["Check permissions on the .beads directory and fix ownership: ls -la <dir>/.beads; chown/chmod as needed.","Inspect what config.yaml actually is (file vs directory): if it is a directory, remove or rename it and recreate the file.","Verify the mount is writable and healthy (dmesg / remount rw) if on NFS/network storage.","Read the wrapped %w cause in the message for the exact errno and address it directly."],"exampleFix":"// before (config.yaml is a directory)\nrm -rf /proj/.beads/config.yaml\n// after\nrm -rf /proj/.beads/config.yaml\nbd init   # recreates config.yaml as a regular file","handlingStrategy":"try-catch","validationCode":"fi, err := os.Lstat(filepath.Join(beadsDir, \"config.yaml\"))\nif err == nil && fi.IsDir() {\n    return fmt.Errorf(\"%s is a directory, expected a file\", fi.Name())\n}\nif err := unix.Access(beadsDir, unix.W_OK); err != nil {\n    return fmt.Errorf(\".beads dir not writable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"err := config.SetYamlConfigInDir(dir, key, value)\nvar pe *fs.PathError\nif errors.As(err, &pe) {\n    return fmt.Errorf(\"filesystem problem at %s (%v): check permissions/mount\", pe.Path, pe.Err)\n}","preventionTips":["Keep config.yaml a regular file; never mkdir over it.","Normalize ownership after sudo/root runs (chown -R $USER .beads).","Avoid keeping .beads on flaky network mounts; use local disk.","Check the wrapped cause (%w) for the exact errno before retrying."],"tags":["config","filesystem","permissions"],"backgroundTag":"stat-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}