{"record":{"id":"6b84df75f9015296","repo":"gastownhall/beads","slug":"serializing-waits-for-also-blocks-metadata-w","errorCode":null,"errorMessage":"serializing waits-for also_blocks metadata: %w","messagePattern":"serializing waits-for also_blocks metadata: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/types/types.go","lineNumber":1434,"sourceCode":"// metadata so waitsForGateBlockedSQL additionally blocks while the spawner\n// itself is open, not only while it has an open parent-child child. Use this\n// instead of NewWaitsForDependency exactly when the caller is collapsing a\n// would-be DepBlocks edge (from needs/depends_on) into this waits-for edge\n// because the two would otherwise collide on the same (source, target) pair\n// — never for a plain waits_for with no matching needs/depends_on entry.\nfunc NewWaitsForBlockingDependency(issueID, spawnerID, gate string) (*Dependency, error) {\n\tdep, err := NewWaitsForDependency(issueID, spawnerID, gate)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar meta WaitsForMeta\n\tif err := json.Unmarshal([]byte(dep.Metadata), &meta); err != nil {\n\t\treturn nil, fmt.Errorf(\"parsing waits-for metadata to set also_blocks: %w\", err)\n\t}\n\tmeta.AlsoBlocks = true\n\traw, err := json.Marshal(meta)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"serializing waits-for also_blocks metadata: %w\", err)\n\t}\n\tdep.Metadata = string(raw)\n\treturn dep, nil\n}\n\n// NewGraphNodeDependency builds the dependency record for a graph-plan node's\n// inline dep, shared by the embedded and domain apply paths so their\n// resolution semantics cannot drift: an empty type defaults to blocks, and\n// the target resolves as a plan-local key first, then as a literal issue ID.\n// Waits-for deps carry gate metadata like waits-for edges (all-children\n// default, no explicit spawner).\nfunc NewGraphNodeDependency(issueID string, depType DependencyType, target string, keyToID map[string]string) (*Dependency, error) {\n\tif depType == \"\" {\n\t\tdepType = DepBlocks\n\t}\n\ttargetID := keyToID[target]\n\tif targetID == \"\" {\n\t\ttargetID = target","sourceCodeStart":1416,"sourceCodeEnd":1452,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/types/types.go#L1416-L1452","documentation":"After adding also_blocks=true to WaitsForMeta, NewWaitsForBlockingDependency re-serializes the struct with json.Marshal; a marshal error is wrapped with this message and returned.","triggerScenarios":"json.Marshal(meta) failing after meta.AlsoBlocks was set to true inside NewWaitsForBlockingDependency.","commonSituations":"Theoretically unreachable: WaitsForMeta holds only string and bool fields which always marshal successfully; would imply a non-standard build or custom marshaler.","solutions":["Rebuild the binary to rule out a patched types package","Check for a custom MarshalJSON on WaitsForMeta and remove it","File an upstream issue with the inner wrapped error if it reproduces on a stock build"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"dep, err := types.NewWaitsForBlockingDependency(issueID, spawnerID, gate)\nif err != nil {\n\tif strings.Contains(err.Error(), \"serializing waits-for also_blocks\") {\n\t\tlog.Fatalf(\"also_blocks metadata serialization failed: %v\", err)\n\t}\n\treturn err\n}","preventionTips":["Avoid custom marshalers on WaitsForMeta","Use a stock build; rebuild if this fires unexpectedly"],"tags":["go","json","serialization","waits-for"],"backgroundTag":"json-marshal-failure","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}