gastownhall/beads · error

failed to get issue %s: %w

Error message

failed to get issue %s: %w

What it means

runUnrelate (bd unrelate) looks up both endpoint issues before removing a relates-to link; this wraps a store.GetIssue error for the first ID. Unlike 'issue not found', the storage layer returned a real error — the lookup itself failed, so bd cannot tell whether the issue exists.

Source

Thrown at cmd/bd/relate.go:178

	var err error
	id1, err = utils.ResolvePartialID(ctx, store, args[0])
	if err != nil {
		return fmt.Errorf("failed to resolve %s: %w", args[0], err)
	}
	id2, err = utils.ResolvePartialID(ctx, store, args[1])
	if err != nil {
		return fmt.Errorf("failed to resolve %s: %w", args[1], err)
	}

	// Get both issues
	var issue1, issue2 *types.Issue
	issue1, err = store.GetIssue(ctx, id1)
	if err != nil {
		return fmt.Errorf("failed to get issue %s: %w", id1, err)
	}
	issue2, err = store.GetIssue(ctx, id2)
	if err != nil {
		return fmt.Errorf("failed to get issue %s: %w", id2, err)
	}

	if issue1 == nil {
		return fmt.Errorf("issue not found: %s", id1)
	}
	if issue2 == nil {
		return fmt.Errorf("issue not found: %s", id2)
	}

	// Remove relates-to dependency in both directions
	// Per Decision 004, relates-to links are now stored in dependencies table.
	// bd unrelate is an explicit dependency verb, so it records history
	// (EmitEvent) like bd dep remove; only structural teardown stays silent.
	// Remove id1 -> id2
	if err := store.RemoveDependencyWithOptions(ctx, id1, id2, actor, storage.DependencyRemoveOptions{EmitEvent: true}); err != nil {
		return fmt.Errorf("failed to remove relates-to %s -> %s: %w", id1, id2, err)
	}
	// Remove id2 -> id1 (bidirectional)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped inner error — it identifies the storage failure (locked DB, I/O error, corruption); fix that root cause first.
  2. If the database is locked, wait for the concurrent `bd` command / `bd dolt` sync to finish and retry; avoid running writers in parallel on the same repo.
  3. Verify database integrity with `bd doctor` and restore from backup (or re-clone the repo and re-sync) if corruption is reported.
  4. Retry the unrelate command — transient I/O or context timeouts often succeed on a second attempt.
  5. Confirm you are running bd in the repository that actually contains the issues, not a stale copy of .beads.

Example fix

// before
$ bd unrelate bd-1 bd-2   # while `bd dolt pull` holds the DB
failed to get issue bd-1: database is locked
// after
$ bd dolt pull && bd unrelate bd-1 bd-2
Defensive patterns

Strategy: try-catch

Validate before calling

for _, id := range []string{id1, id2} {
	if !strings.HasPrefix(id, "bd-") {
		return fmt.Errorf("%q does not look like an issue id", id)
	}
}
if _, err := os.Stat(filepath.Join(repoRoot, ".beads")); err != nil {
	return fmt.Errorf("no beads database in %s", repoRoot)
}

Try / catch

issue, err := store.GetIssue(ctx, id)
if err != nil {
	if errors.Is(err, ErrDatabaseLocked) || isTransient(err) {
		// wait for concurrent writer / sync, then retry once
		time.Sleep(time.Second)
		issue, err = store.GetIssue(ctx, id)
	}
	if err != nil {
		return fmt.Errorf("failed to get issue %s: %w", id, err)
	}
}

Prevention

When it happens

Trigger: store.GetIssue(ctx, id1) returns a non-nil error: database file locked or corrupted, storage/driver failure, context cancellation mid-query, or an underlying SQL/driver error while reading the issues table.

Common situations: Another bd process or sync operation holding the database; a crashed writer leaving the Dolt/SQLite store inconsistent; network filesystem hosting .beads dropped mid-command; running bd while a migration is in progress.

Related errors


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