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 spawnerView on GitHub (pinned to 71377f2769)
Solutions
- Rebuild the binary / clear build cache to rule out a stale or patched types package
- If it persists, check for any custom MarshalJSON override on WaitsForMeta and remove it
- 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
- Do not add custom MarshalJSON to WaitsForMeta
- Rebuild from a clean checkout if this ever fires
- Include the wrapped inner error in bug reports
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
- serializing waits-for also_blocks metadata: %w
- failed to marshal backup state: %w
- failed to marshal issue %s: %w
- failed to marshal interactions log entry: %w
- marshal create request: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/7477c0e8781bb33a.
Report an issue: GitHub.