gastownhall/beads · error

failed to add supersede link: %w

Error message

failed to add supersede link: %w

What it means

After validating the replacement, runSupersede inserts a DepSupersedes dependency edge (old -> new) via store.AddDependency. Any storage-layer failure is wrapped with this message so the caller knows the supersede link — not the issue lookup or the close step — failed. The command aborts before closing the old issue, leaving both issues open.

Source

Thrown at cmd/bd/duplicate.go:177

	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)
	}

	commandDidWrite.Store(true)

	if isJSONOutput() {
		return outputJSON(map[string]interface{}{
			"superseded":  oldID,
			"replacement": newID,
			"status":      "closed",
		})
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped %w cause to identify the storage error
  2. Check the dependency does not already exist (`bd deps <oldID>` / `bd blocked-by`)
  3. Re-run the command after resolving the transient DB condition; AddDependency failure means the old issue was NOT closed, so re-running is safe
  4. Run `bd doctor` to diagnose database connectivity
Defensive patterns

Strategy: try-catch

Validate before calling

deps, _ := runBdOutput("deps", oldID) // ensure no conflicting supersedes edge exists yet

Try / catch

if err := runSupersede(ctx, oldID, newID, actor); err != nil {
    var wrapped interface{ Unwrap() error }
    if errors.As(err, &target) { /* inspect storage cause */ }
    log.Warnw("supersede link failed; old issue left open", "err", err)
}

Prevention

When it happens

Trigger: AddDependency returns an error: duplicate/self-referential dependency rejected, dependency cycle detected, store not initialized, or an underlying Dolt/driver write error during the transaction.

Common situations: Superseding an issue that already depends on the replacement (cycle or duplicate edge); database locked by another writer; write attempted in read-only or server-unreachable mode.

Related errors


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