gastownhall/beads · error

replacement issue not found: %s

Error message

replacement issue not found: %s

What it means

runSupersede resolves the replacement issue via store.GetIssue before wiring a supersedes dependency. When GetIssue returns an error or a nil issue, the command aborts so it never creates a supersede edge pointing at a nonexistent issue. This protects the dependency graph from dangling references.

Source

Thrown at cmd/bd/duplicate.go:167

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

	if oldID == newID {
		return fmt.Errorf("cannot mark an issue as superseded by itself")
	}

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

	// Add a "supersedes" dependency edge (old → new)
	dep := &types.Dependency{
		IssueID:     oldID,
		DependsOnID: newID,
		Type:        types.DepSupersedes,
	}
	if err := store.AddDependency(ctx, dep, actor); err != nil {
		return fmt.Errorf("failed to add supersede link: %w", err)
	}

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

View on GitHub (pinned to 71377f2769)

Solutions

  1. Verify the replacement ID with `bd show <newID>` before running supersede
  2. Run `bd dolt pull` / re-sync so the replacement issue exists locally
  3. Check you are in the repo/directory backed by the intended beads database
  4. Create the replacement issue first with `bd create` if it does not exist yet

Example fix

// before
newIssue, err = store.GetIssue(ctx, newID)
// after
// ensure the replacement exists (and surface the real storage error)
newIssue, err = store.GetIssue(ctx, newID)
if err != nil { return fmt.Errorf("lookup replacement %s: %w", newID, err) }
if newIssue == nil { return fmt.Errorf("replacement issue not found: %s (run `bd show %s` to verify)", newID, newID) }
Defensive patterns

Strategy: validation

Validate before calling

// before supersede
if out, err := exec.Command("bd", "show", newID).CombinedOutput(); err != nil {
    return fmt.Errorf("replacement %s does not exist: %s", newID, out)
}

Try / catch

if err := runSupersede(ctx, oldID, newID); err != nil {
    if strings.Contains(err.Error(), "replacement issue not found") {
        // correct the ID / create the issue, then retry
    }
}

Prevention

When it happens

Trigger: Running `bd supersede OLD NEW` where NEW does not exist in the store, NEW was deleted, the ID is misspelled or from another database, or GetIssue fails on a transient storage error (including err==nil with nil issue).

Common situations: Typo in the replacement issue ID; replacing across two separate beads databases; the replacement issue was closed-and-deleted by a cleanup/prune job; stale Dolt sync left the local DB without the issue.

Related errors


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