gastownhall/beads · error

failed to parse config.yaml: %w

Error message

failed to parse config.yaml: %w

What it means

GetReposFromYAML unmarshals config.yaml into a generic map; this error wraps any yaml.Unmarshal failure, meaning the file exists and is readable but is not valid YAML (or the top level is not a mapping).

Source

Thrown at internal/config/repos.go:47

	}
	return configPath, nil
}

// GetReposFromYAML reads the repos configuration from config.yaml
// Returns an empty ReposConfig if repos section doesn't exist
func GetReposFromYAML(configPath string) (*ReposConfig, error) {
	data, err := os.ReadFile(configPath) // #nosec G304 - config file path from caller
	if err != nil {
		if os.IsNotExist(err) {
			return &ReposConfig{}, nil
		}
		return nil, fmt.Errorf("failed to read config.yaml: %w", err)
	}

	// Parse into a generic map to extract repos section
	var cfg map[string]interface{}
	if err := yaml.Unmarshal(data, &cfg); err != nil {
		return nil, fmt.Errorf("failed to parse config.yaml: %w", err)
	}

	repos := &ReposConfig{}
	if reposRaw, ok := cfg["repos"]; ok && reposRaw != nil {
		reposMap, ok := reposRaw.(map[string]interface{})
		if !ok {
			return nil, fmt.Errorf("repos section is not a map")
		}

		if primary, ok := reposMap["primary"].(string); ok {
			repos.Primary = primary
		}

		if additional, ok := reposMap["additional"]; ok && additional != nil {
			switch v := additional.(type) {
			case []interface{}:
				for _, item := range v {
					if str, ok := item.(string); ok {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Validate the YAML with a linter: yamllint .beads/config.yaml or an online parser.
  2. Fix indentation — use spaces, never tabs — and remove merge-conflict markers.
  3. Restore a known-good config from git: git checkout -- .beads/config.yaml or git diff to see what changed.
  4. If unparseable content is unrecoverable, back it up and re-run `bd init` to regenerate.

Example fix

// before (broken)
repos:
	primary: "."
// after
repos:
  primary: "."
  additional:
    - "../other-repo"
Defensive patterns

Strategy: validation

Validate before calling

data, err := os.ReadFile(".beads/config.yaml")
if err == nil {
    var probe map[string]interface{}
    if err := yaml.Unmarshal(data, &probe); err != nil {
        return fmt.Errorf("config.yaml is invalid YAML: %w", err)
    }
}

Try / catch

repos, err := config.GetReposFromYAML(configPath)
if err != nil && strings.Contains(err.Error(), "failed to parse config.yaml") {
    return fmt.Errorf("config.yaml is malformed; restore from git: %w", err)
}

Prevention

When it happens

Trigger: Calling GetReposFromYAML(configPath) where the file contains malformed YAML — bad indentation, tabs instead of spaces, unterminated quotes, duplicate keys rejected by yaml.v3, or a top-level scalar/list instead of a mapping.

Common situations: Hand-editing config.yaml and breaking indentation; merging conflicts leaving conflict markers (<<<<<<<) in the file; a tool writing non-YAML content into config.yaml; pasting JSON with tabs or trailing issues.

Understand the failure class

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/1661f040f44d7b98. Report an issue: GitHub.