gastownhall/beads · error

node %q: updating metadata refs: %w

Error message

node %q: updating metadata refs: %w

What it means

The follow-up `tx.UpdateIssue` that writes merged metadata back onto the freshly created issue failed. This is a storage-layer write failure specific to the metadata-ref step, wrapped with the node key; the transaction rolls back all created nodes.

Source

Thrown at cmd/bd/graph_apply.go:985

		for i, node := range plan.Nodes {
			keyToID[node.Key] = issues[i].ID
		}

		// Resolve MetadataRefs now that all IDs are known.
		for i, node := range plan.Nodes {
			if len(node.MetadataRefs) == 0 {
				continue
			}
			metaJSON, err := types.MergeMetadataRefs(issues[i].Metadata, node.MetadataRefs, keyToID)
			if err != nil {
				return fmt.Errorf("node %q: %w", node.Key, err)
			}
			updates := map[string]interface{}{
				"metadata": metaJSON,
			}
			if err := tx.UpdateIssue(ctx, issues[i].ID, updates, actor); err != nil {
				return fmt.Errorf("node %q: updating metadata refs: %w", node.Key, err)
			}
		}

		parentDepPairs := graphApplyParentDepPairs(plan.Nodes, keyToID)
		newSchedulingEdges := make([][2]string, 0, len(plan.Nodes)+len(plan.Edges))
		if err := validateGraphApplyPlannedParentBlockingPaths(ctx, tx, plan, keyToID, parentDepPairs); err != nil {
			return err
		}
		if err := validateGraphApplyPlannedBlockingCycles(ctx, tx, plan, keyToID); err != nil {
			return err
		}
		for i, edge := range plan.Edges {
			fromID := resolveEdgeRef(edge.FromKey, edge.FromID, keyToID)
			toID := resolveEdgeRef(edge.ToKey, edge.ToID, keyToID)
			depType := graphApplyDependencyType(edge.Type)
			if parentDepPairs[graphApplyDepPairKey(fromID, toID)] && depType != types.DepParentChild {
				return fmt.Errorf("edge %d %s->%s duplicates a parent-child relationship with dependency type %q", i, fromID, toID, depType)
			}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped inner error for the storage cause.
  2. Check Dolt/server health and connectivity, then re-run the apply.
  3. Retry after resolving contention; the rollback makes re-application safe.
  4. If persistent, verify no other process holds locks on the database.
Defensive patterns

Strategy: retry

Try / catch

err := bd.GraphApply(ctx, plan)
if err != nil && strings.Contains(err.Error(), "updating metadata refs") {
  // transaction rolled back; check storage health then retry
  return retryWithBackoff(func() error { _, err := bd.GraphApply(ctx, plan); return err }, 3)
}

Prevention

When it happens

Trigger: Driver/Dolt error during UpdateIssue: backend unavailable, row locked, I/O error, or the update payload rejected by the driver.

Common situations: Dolt server connection dropped mid-transaction; disk full; concurrent writer contending on the same issue row.

Related errors


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