{"record":{"id":"fe58d5124da3808c","repo":"gastownhall/beads","slug":"failed-to-read-config-yaml-w-fe58d5","errorCode":null,"errorMessage":"failed to read config.yaml: %w","messagePattern":"failed to read config\\.yaml: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/yaml_config.go","lineNumber":515,"sourceCode":"\tif _, err := os.Stat(configPath); os.IsNotExist(err) {\n\t\tif err := os.WriteFile(configPath, []byte{}, 0o600); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create user config.yaml: %w\", err)\n\t\t}\n\t} else if err != nil {\n\t\treturn fmt.Errorf(\"failed to stat user config.yaml: %w\", err)\n\t}\n\treturn setYamlConfigAtPath(configPath, key, value)\n}\n\nfunc setYamlConfigAtPath(configPath, key, value string) error {\n\n\t// Normalize key to canonical yaml format\n\tnormalizedKey := normalizeYamlKey(key)\n\n\t// Read existing config\n\tcontent, err := os.ReadFile(configPath) //nolint:gosec // configPath is from findProjectConfigYaml\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read config.yaml: %w\", err)\n\t}\n\n\t// Update or add the key\n\tnewContent, err := updateYamlKey(string(content), normalizedKey, value)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Write back\n\tif err := os.WriteFile(configPath, []byte(newContent), 0600); err != nil { //nolint:gosec // configPath is validated\n\t\treturn fmt.Errorf(\"failed to write config.yaml: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// GetYamlConfig gets a configuration value from config.yaml.\n// Returns empty string if key is not found or is commented out.","sourceCodeStart":497,"sourceCodeEnd":533,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/config/yaml_config.go#L497-L533","documentation":"setYamlConfigAtPath wraps any os.ReadFile failure on the target config.yaml path before updating a key. The wrapped cause (%w) is the underlying OS error, so the real reason (missing file, permissions, path) is in the %w suffix. bd throws it because YAML config writes require reading the existing file to merge the new key into it.","triggerScenarios":"Calling SetYamlConfig, SetYamlConfigInDir, or SetUserYamlConfig when the resolved config.yaml path does not exist (project not initialized) or cannot be opened (permissions, path is a directory, race where the file is deleted between resolution and read).","commonSituations":"Running 'bd config set' in a repo where 'bd init' was never run; BEADS_DIR pointing at a directory without config.yaml; config.yaml with restrictive ownership after switching users or cloning without the file.","solutions":["Run 'bd init' in the project (or in the directory BEADS_DIR points at) to create .beads/config.yaml","Check the wrapped error in the %w suffix: if 'no such file or directory', create the file; if 'permission denied', fix ownership/permissions (chmod/chown)","Verify BEADS_DIR points to the correct directory containing config.yaml, or unset it to use project resolution","Ensure config.yaml is a regular readable file, not a directory, symlink, or FIFO"],"exampleFix":"// before (fails: file never created)\nBEADS_DIR=/tmp/myrepo bd config set dolt.mode embedded\n// after\nbd init /tmp/myrepo && bd config set dolt.mode embedded","handlingStrategy":"try-catch","validationCode":"path, err := findProjectConfigYaml()\nif err != nil { return err }\nif _, err := os.Stat(path); err != nil {\n    return fmt.Errorf(\"config.yaml missing at %s: run 'bd init' first\", path)\n}","typeGuard":"func configReadable(path string) bool {\n    fi, err := os.Stat(path)\n    return err == nil && fi.Mode().IsRegular()\n}","tryCatchPattern":"if err := SetYamlConfig(key, value); err != nil {\n    var perr *fs.PathError\n    if errors.As(err, &perr) && os.IsNotExist(err) {\n        // run bd init or create config.yaml, then retry\n    }\n    return err\n}","preventionTips":["Always run 'bd init' before any config set/unset command","Check BEADS_DIR points at an initialized directory in setup scripts","Verify config.yaml exists and is readable before scripted config changes"],"tags":["config","file-io","go"],"backgroundTag":"config-file-read-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}