gastownhall/beads · error

coordinate issue create: %w

Error message

coordinate issue create: %w

What it means

EnsureIssueIDAvailableInTx fails while writing the per-ID coordination row into local_metadata (REPLACE INTO local_metadata). This write serializes same-shard creates so two concurrent creates of the same ID cannot interleave; failure means the underlying transaction/DB rejected the write.

Source

Thrown at internal/storage/issueops/create_only_guard.go:22

	"context"
	"crypto/sha256"
	"fmt"
	"strconv"

	"github.com/steveyegge/beads/internal/storage"
)

// EnsureIssueIDAvailableInTx serializes same-shard creates and rejects occupied IDs.
func EnsureIssueIDAvailableInTx(ctx context.Context, tx DBTX, id string) error {
	if tx == nil {
		return fmt.Errorf("ensure issue ID available: transaction is nil")
	}
	if id == "" {
		return fmt.Errorf("ensure issue ID available: ID is empty")
	}
	key := issueCreateCoordinationKey(id)
	if _, err := tx.ExecContext(ctx, "REPLACE INTO local_metadata (`key`, value) VALUES (?, ?)", key, strconv.FormatInt(FreshRowLock(), 10)); err != nil {
		return fmt.Errorf("coordinate issue create: %w", err)
	}
	for _, table := range []string{"issues", "wisps"} {
		var count int
		if err := tx.QueryRowContext(ctx, "SELECT COUNT(*) FROM "+table+" WHERE id = ?", id).Scan(&count); err != nil {
			return fmt.Errorf("check %s for issue %q: %w", table, id, err)
		}
		if count > 0 {
			return fmt.Errorf("%w: %s", storage.ErrAlreadyExists, id)
		}
	}
	return nil
}

func issueCreateCoordinationKey(id string) string {
	sum := sha256.Sum256([]byte(id))
	shard := uint16(sum[0])<<4 | uint16(sum[1])>>4
	return fmt.Sprintf("issue-create/v1/%03x", shard)
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped driver error via errors.Unwrap to identify the storage-level cause
  2. Retry the whole transaction with a fresh tx handle; never reuse a failed tx
  3. Reduce transaction scope/duration so the connection does not time out before the guard runs

Example fix

// before
err := EnsureIssueIDAvailableInTx(ctx, staleTx, id) // tx already rolled back
// after
tx, err := db.BeginTx(ctx, nil)
if err != nil { return err }
err = EnsureIssueIDAvailableInTx(ctx, tx, id)
Defensive patterns

Strategy: retry

Try / catch

if err := EnsureIssueIDAvailableInTx(ctx, tx, id); err != nil {
    if strings.HasPrefix(err.Error(), "coordinate issue create:") {
        cause := errors.Unwrap(err) // inspect driver error
        // abandon tx, begin a new one, retry once
    }
    return err
}

Prevention

When it happens

Trigger: The tx handle is dead or already failed (rolled back, closed connection); storage backend error on the local_metadata REPLACE; context canceled mid-exec.

Common situations: Long transactions that hit connection timeouts before reaching the guard; a DB in read-only or locked state; driver-level errors during concurrent batch imports.

Related errors


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