gastownhall/beads · error

touch dependency coordination for %s: %w

Error message

touch dependency coordination for %s: %w

What it means

This wraps the underlying SQL error from the REPLACE INTO local_metadata statement that records a fresh coordination/row-lock timestamp for the dependency table. The library wraps (%w) the driver error while naming the affected table so callers can distinguish which dependency tier failed to be touched. It indicates the local metadata write failed at the storage level, not a caller mistake.

Source

Thrown at internal/storage/issueops/dependency_coordination.go:43

			return err
		}
	}
	return nil
}

// TouchDependencyCoordinationTableInTx rewrites the coordination cell for one
// dependency table. table must be dependencies or wisp_dependencies.
func TouchDependencyCoordinationTableInTx(ctx context.Context, tx DBTX, parentID, table string) error {
	if parentID == "" {
		return fmt.Errorf("touch dependency coordination: parent ID must not be empty")
	}
	if table != dependencyCoordinationDurableTier && table != dependencyCoordinationEphemeralTier {
		return fmt.Errorf("touch dependency coordination: unsupported table %q", table)
	}
	key := dependencyCoordinationKey(parentID, table)
	if _, err := tx.ExecContext(ctx,
		"REPLACE INTO local_metadata (`key`, value) VALUES (?, ?)", key, strconv.FormatInt(FreshRowLock(), 10)); err != nil {
		return fmt.Errorf("touch dependency coordination for %s: %w", table, err)
	}
	return nil
}

func dependencyCoordinationKey(parentID, table string) string {
	shard := dependencyCoordinationShard(parentID)
	// A tier has 4096 shard rows: enough to keep unrelated writes apart while
	// bounding the clone-local coordination state at 8192 rows. Same-parent
	// operations always resolve to the same shard; a hash collision only adds a
	// safe serialization conflict.
	return fmt.Sprintf("%s%s/%s/%03x", dependencyCoordinationKeyPrefix, dependencyCoordinationKeyVersion, table, shard)
}

func dependencyCoordinationShard(parentID string) uint16 {
	sum := sha256.Sum256([]byte(parentID))
	return uint16(sum[0])<<4 | uint16(sum[1])>>4
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped root cause — it identifies the driver/SQL failure.
  2. Verify the local_metadata table exists with columns `key` and `value` (bd doctor / schema check).
  3. Check that no earlier statement in the same transaction failed and poisoned the tx.
  4. Retry on transient errors; if persistent, confirm the database isn't read-only or locked.
Defensive patterns

Strategy: retry

Validate before calling

// verify local_metadata exists before writing
var one int
if err := tx.QueryRowContext(ctx,
    "SELECT 1 FROM local_metadata LIMIT 1").Scan(&one); err != nil {
    return fmt.Errorf("local_metadata unavailable: %w", err)
}

Try / catch

if err := TouchDependencyCoordinationTableInTx(ctx, tx, parentID, table); err != nil {
    if isTransientSQLErr(err) { err = TouchDependencyCoordinationTableInTx(ctx, tx, parentID, table) }
    if err != nil { return fmt.Errorf("coordination touch failed: %w", err) }
}

Prevention

When it happens

Trigger: Calling TouchDependencyCoordinationTableInTx when the local_metadata table is missing/locked, the transaction is already aborted, or the Dolt driver rejects the write (schema mismatch, disk, connection failure).

Common situations: Schema drift where local_metadata doesn't exist in an old database; transaction already rolled back due to an earlier error in the same tx; write contention or read-only database.

Related errors


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