{"record":{"id":"213bf9f9dbf137b6","repo":"gastownhall/beads","slug":"edge-d-spawner-key-q-must-match-to-key-q-the","errorCode":null,"errorMessage":"edge %d: spawner_key %q must match to_key %q (the waits-for target is the spawner)","messagePattern":"edge (.+?): spawner_key %q must match to_key %q \\(the waits-for target is the spawner\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/graph_apply.go","lineNumber":632,"sourceCode":"\t\t\t}\n\t\t\tif edge.Gate != \"\" && !types.IsValidWaitsForGate(edge.Gate) {\n\t\t\t\treturn fmt.Errorf(\"edge %d: invalid gate %q (valid: %s, %s)\", i, edge.Gate, types.WaitsForAllChildren, types.WaitsForAnyChildren)\n\t\t\t}\n\t\t\tif edge.SpawnerKey != \"\" && edge.SpawnerID != \"\" {\n\t\t\t\treturn fmt.Errorf(\"edge %d: cannot specify both spawner_key and spawner_id\", i)\n\t\t\t}\n\t\t\tif edge.SpawnerKey != \"\" && !seenKeys[edge.SpawnerKey] {\n\t\t\t\treturn fmt.Errorf(\"edge %d: spawner key %q not found in plan\", i, edge.SpawnerKey)\n\t\t\t}\n\t\t\t// Gate evaluation reads the spawner from the dependency target\n\t\t\t// (depends_on_id), not metadata, so the spawner must equal the to\n\t\t\t// endpoint. Since to_id overrides to_key at apply time\n\t\t\t// (resolveEdgeRef), a key-named spawner can't be combined with to_id.\n\t\t\tif edge.SpawnerKey != \"\" && edge.ToID != \"\" {\n\t\t\t\treturn fmt.Errorf(\"edge %d: spawner_key %q cannot be combined with to_id %q (to_id overrides to_key as the waits-for target; use spawner_id)\", i, edge.SpawnerKey, edge.ToID)\n\t\t\t}\n\t\t\tif edge.SpawnerKey != \"\" && edge.SpawnerKey != edge.ToKey {\n\t\t\t\treturn fmt.Errorf(\"edge %d: spawner_key %q must match to_key %q (the waits-for target is the spawner)\", i, edge.SpawnerKey, edge.ToKey)\n\t\t\t}\n\t\t\tif edge.SpawnerID != \"\" && edge.SpawnerID != edge.ToID {\n\t\t\t\treturn fmt.Errorf(\"edge %d: spawner_id %q must match to_id %q (the waits-for target is the spawner)\", i, edge.SpawnerID, edge.ToID)\n\t\t\t}\n\t\t}\n\t}\n\n\tif err := validateGraphApplyLocalCycles(plan, seenKeys); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// validateGraphApplyNodeFields checks the single-node fields added for\n// bd-create parity, mirroring the flag-shape checks `bd create` applies\n// (config-gated template linting is not run on graph plans).\nfunc validateGraphApplyNodeFields(node GraphApplyNode, customTypes, customStatuses []string, opts GraphApplyOptions) error {","sourceCodeStart":614,"sourceCodeEnd":650,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/graph_apply.go#L614-L650","documentation":"For waits-for edges the spawner IS the dependency target: the waits-for target is the node that spawns/parented the waiter. If spawner_key differs from to_key, the edge semantics are inconsistent and validation rejects it.","triggerScenarios":"An edge with type waits-for where spawner_key = \"x\" but to_key = \"y\" (x != y).","commonSituations":"Authoring waits-for edges between arbitrary nodes as if they were plain dependencies; copy-pasting a dependency edge and changing to_key without updating spawner_key; misunderstanding waits-for semantics.","solutions":["Set spawner_key equal to to_key (the waits-for target is the spawner)","Or remove the spawner fields if you want a plain waits-for without gate semantics","If you intended a non-spawner dependency, use a different dependency type"],"exampleFix":"// before\n{\"type\": \"waits-for\", \"spawner_key\": \"parent-a\", \"to_key\": \"sibling-b\"}\n// after\n{\"type\": \"waits-for\", \"spawner_key\": \"sibling-b\", \"to_key\": \"sibling-b\"}","handlingStrategy":"validation","validationCode":"if e.Type == \"waits-for\" && e.SpawnerKey != \"\" && e.SpawnerKey != e.ToKey {\n  return fmt.Errorf(\"spawner_key must equal to_key for waits-for edges\")\n}","typeGuard":"func spawnerMatchesTarget(e Edge) bool { return e.SpawnerKey == \"\" || e.SpawnerKey == e.ToKey }","tryCatchPattern":null,"preventionTips":["Treat waits-for spawner as the to endpoint, not an arbitrary third node","Use plain dependency types when the target is not the spawner","Template waits-for edges as a single unit (spawner == target)"],"tags":["graph-plan","waits-for","spawner"],"backgroundTag":"spawner-target-mismatch","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}