gastownhall/beads · error

no config.yaml found in %s (run 'bd init' first)

Error message

no config.yaml found in %s (run 'bd init' first)

What it means

SetYamlConfigInDir writes a key/value into the config.yaml inside a given .beads directory, but only updates existing files — it never creates one. When config.yaml is absent from beadsDir it throws this error telling the user to run 'bd init' first.

Source

Thrown at internal/config/yaml_config.go:294

	}

	return setYamlConfigAtPath(configPath, key, value)
}

// SetYamlConfigInDir sets a configuration value in the config.yaml located in
// the provided beadsDir, bypassing CWD/worktree discovery. Use this when the
// caller has already resolved the authoritative workspace and needs to avoid
// local worktree stubs shadowing the real shared config location.
func SetYamlConfigInDir(beadsDir, key, value string) error {
	// Validate specific keys (GH#995)
	if err := validateYamlConfigValue(key, value); err != nil {
		return err
	}

	configPath := filepath.Join(beadsDir, "config.yaml")
	if _, err := os.Stat(configPath); err != nil {
		if os.IsNotExist(err) {
			return fmt.Errorf("no config.yaml found in %s (run 'bd init' first)", beadsDir)
		}
		return fmt.Errorf("failed to stat config.yaml: %w", err)
	}

	return setYamlConfigAtPath(configPath, key, value)
}

var userGlobalKeyPrefixes = []string{"metrics."}

// userGlobalExactKeys are per-MACHINE settings that must never be written to
// the project .beads/config.yaml, which is a git-TRACKED file (see
// cmd/bd/doctor/gitignore.go: nothing in .beads/.gitignore excludes it). A
// committed value propagates one machine's answer to every clone that pulls
// it, which for these keys is worse than having no value at all.
//
// node_id is the exemplar: it names the beads STORE that grants leases here,
// and the reclaim guard (issueops.ReclaimExpiredLeasesInTx) compares it
// against each lease's granted_node. Commit "node_id: mini" and every replica

View on GitHub (pinned to 71377f2769)

Solutions

  1. Run `bd init` in the target directory to create .beads/config.yaml, then retry the config set.
  2. Verify you are in the correct project directory (config.yaml must exist at <dir>/.beads/config.yaml).
  3. If the file was deleted, restore it from version control or another checkout.
  4. Create a minimal empty config.yaml manually if init is not desired, then set the key.

Example fix

// before
SetYamlConfigInDir("/proj/.beads", "metrics.enabled", "true") // no config.yaml
// after
// run once in /proj:
//   bd init
SetYamlConfigInDir("/proj/.beads", "metrics.enabled", "true")
Defensive patterns

Strategy: validation

Validate before calling

func ensureInitialized(beadsDir string) error {
    if _, err := os.Stat(filepath.Join(beadsDir, "config.yaml")); os.IsNotExist(err) {
        return fmt.Errorf("run 'bd init' in %s first", beadsDir)
    }
    return nil
}

Try / catch

err := config.SetYamlConfigInDir(dir, key, value)
if err != nil && strings.Contains(err.Error(), "run 'bd init' first") {
    if out, initErr := exec.Command("bd", "init").CombinedOutput(); initErr != nil {
        return fmt.Errorf("init failed: %v: %s", initErr, out)
    }
    return config.SetYamlConfigInDir(dir, key, value)
}

Prevention

When it happens

Trigger: Calling SetYamlConfigInDir(dir, key, value) (or bd config set against a project) where os.Stat(filepath.Join(beadsDir, "config.yaml")) returns os.IsNotExist — i.e. the .beads directory exists but was never initialized, or the wrong directory was passed.

Common situations: Running bd config set in a directory without a prior bd init; pointing bd at a copied/synced .beads dir missing config.yaml; typos in BEADS_DIR or cwd.

Related errors


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