gastownhall/beads · error

serializing waits-for metadata: %w

Error message

serializing waits-for metadata: %w

What it means

NewGraphEdgeDependency serializes the WaitsForMeta struct (gate + spawnerID) into the dependency's metadata JSON for waits-for edges. If json.Marshal fails — practically impossible for this fixed-structure string struct — the error is wrapped with this message.

Source

Thrown at internal/types/types.go:1398

		IssueID:     fromID,
		DependsOnID: toID,
		Type:        depType,
		ThreadID:    threadID,
	}
	if depType == DepWaitsFor {
		if spawnerKey != "" {
			resolved, ok := keyToID[spawnerKey]
			if !ok {
				return nil, fmt.Errorf("serializing waits-for metadata: unresolved spawner key %q", spawnerKey)
			}
			spawnerID = resolved
		}
		if gate == "" {
			gate = WaitsForAllChildren
		}
		raw, err := json.Marshal(WaitsForMeta{Gate: gate, SpawnerID: spawnerID})
		if err != nil {
			return nil, fmt.Errorf("serializing waits-for metadata: %w", err)
		}
		dep.Metadata = string(raw)
	}
	return dep, nil
}

// NewWaitsForDependency builds the waits-for dependency record for a single
// issue outside a graph plan: the spawner is the depends_on target and the
// metadata carries the gate (defaulted to all-children). Shares
// NewGraphEdgeDependency so single-issue and graph-created waits-for rows
// cannot drift.
func NewWaitsForDependency(issueID, spawnerID, gate string) (*Dependency, error) {
	return NewGraphEdgeDependency(issueID, spawnerID, DepWaitsFor, gate, "", "", "", nil)
}

// NewWaitsForBlockingDependency builds a waits-for dependency that also
// carries classic blocking semantics (GH#3783): set also_blocks in the
// metadata so waitsForGateBlockedSQL additionally blocks while the spawner

View on GitHub (pinned to 71377f2769)

Solutions

  1. Rebuild the binary / clear build cache to rule out a stale or patched types package
  2. If it persists, check for any custom MarshalJSON override on WaitsForMeta and remove it
  3. Report upstream with the wrapped inner error, since stock WaitsForMeta cannot fail to marshal
Defensive patterns

Strategy: try-catch

Validate before calling

// WaitsForMeta is a plain string struct; nothing meaningful to pre-validate.
// Optionally assert the build is stock:
// if !json.Valid([]byte(`{"gate":"all-children","spawner_id":""}`)) { /* non-standard json pkg */ }

Try / catch

dep, err := types.NewGraphEdgeDependency(fromID, toID, depType, gate, spawnerKey, spawnerID, threadID, keyToID)
if err != nil {
	if strings.Contains(err.Error(), "serializing waits-for metadata") {
		log.Fatalf("waits-for metadata serialization failed: %v", err)
	}
	return err
}

Prevention

When it happens

Trigger: json.Marshal(WaitsForMeta{...}) returning a non-nil error inside NewGraphEdgeDependency for a DepWaitsFor edge.

Common situations: Essentially unreachable in practice since WaitsForMeta contains only string fields; would indicate a corrupted build or a custom JSON marshaler on the type.

Related errors


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