gastownhall/beads · error

canonical issue not found: %s

Error message

canonical issue not found: %s

What it means

Raised when store.GetIssue returns an error or nil for the resolved canonical ID in runDuplicate — the canonical issue could not be loaded from the store even though its ID resolved. This catches races (issue deleted between resolve and fetch) and storage read failures, and is reported with the canonical ID. The duplicate is left unmodified.

Source

Thrown at cmd/bd/duplicate.go:97

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

	if duplicateID == canonicalID {
		return fmt.Errorf("cannot mark an issue as duplicate of itself")
	}

	// Verify canonical issue exists
	var canonical *types.Issue
	canonical, err = store.GetIssue(ctx, canonicalID)
	if err != nil || canonical == nil {
		return fmt.Errorf("canonical issue not found: %s", canonicalID)
	}

	// Add a "duplicates" dependency edge (duplicate → canonical)
	dep := &types.Dependency{
		IssueID:     duplicateID,
		DependsOnID: canonicalID,
		Type:        types.DepDuplicates,
	}
	if err := store.AddDependency(ctx, dep, actor); err != nil {
		return fmt.Errorf("failed to add duplicate link: %w", err)
	}

	// Close the duplicate issue through the lifecycle operation so it records
	// the complete closure state.
	if err := store.CloseIssue(ctx, duplicateID, "", actor, ""); err != nil {
		return fmt.Errorf("failed to close duplicate: %w", err)
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Re-run `bd show <canonical-id>` to check the issue still exists
  2. Re-run the duplicate command — a transient storage error may have cleared
  3. Run `bd doctor` / verify store integrity if GetIssue keeps failing
  4. Pick a different canonical issue if the target was deleted

Example fix

// before
$ bd duplicate bd-42 --duplicate-of bd-99  # bd-99 deleted moments ago
Error: canonical issue not found: bd-99
// after
$ bd list | grep bd-  # pick an existing canonical
$ bd duplicate bd-42 --duplicate-of bd-101
Defensive patterns

Strategy: validation

Validate before calling

canonical, err := store.GetIssue(ctx, canonicalID)
if err != nil || canonical == nil {
    return fmt.Errorf("canonical %s missing; pick another with bd list", canonicalID)
}

Type guard

if canonical == nil {
    return fmt.Errorf("canonical issue %s does not exist", canonicalID)
}

Try / catch

canonical, err := store.GetIssue(ctx, canonicalID)
if err != nil {
    if errors.Is(err, ErrKeyNotFound) { return fmt.Errorf("canonical %s deleted", canonicalID) }
    return fmt.Errorf("storage error fetching canonical: %w", err)
}

Prevention

When it happens

Trigger: The canonical issue was deleted or closed/purged between ResolvePartialID and GetIssue; the underlying Dolt/driver read fails; a nil row is returned for the resolved ID.

Common situations: Concurrent deletion by another agent or process in a multi-agent workflow; a stale replica out of sync; storage corruption or driver error surfacing as a GetIssue failure.

Related errors


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