gastownhall/beads · error

edge %d: to key %q not found in plan

Error message

edge %d: to key %q not found in plan

What it means

Plan edges may specify their destination via to_key or to_id. If to_key is set, it must match a node key in the plan; an unknown to_key means the edge target cannot be resolved and the apply is rejected.

Source

Thrown at cmd/bd/graph_apply.go:597

		for j, dep := range node.Deps {
			if dep.Target == "" {
				return fmt.Errorf("node %q: dep %d has empty target", node.Key, j)
			}
			if dep.Type != "" {
				dt := types.DependencyType(dep.Type)
				if !dt.IsValid() {
					return fmt.Errorf("node %q: dep %d: invalid dependency type %q", node.Key, j, dep.Type)
				}
			}
		}
	}

	for i, edge := range plan.Edges {
		if edge.FromKey != "" && !seenKeys[edge.FromKey] {
			return fmt.Errorf("edge %d: from key %q not found in plan", i, edge.FromKey)
		}
		if edge.ToKey != "" && !seenKeys[edge.ToKey] {
			return fmt.Errorf("edge %d: to key %q not found in plan", i, edge.ToKey)
		}
		if edge.FromKey == "" && edge.FromID == "" {
			return fmt.Errorf("edge %d: must specify from_key or from_id", i)
		}
		if edge.ToKey == "" && edge.ToID == "" {
			return fmt.Errorf("edge %d: must specify to_key or to_id", i)
		}
		if edge.Type != "" {
			dt := types.DependencyType(edge.Type)
			if !dt.IsValid() {
				return fmt.Errorf("edge %d: invalid dependency type %q", i, edge.Type)
			}
		}
		if edge.Gate != "" || edge.SpawnerKey != "" || edge.SpawnerID != "" {
			if graphApplyDependencyType(edge.Type) != types.DepWaitsFor {
				return fmt.Errorf("edge %d: gate/spawner fields require type %q", i, types.DepWaitsFor)
			}
			if edge.Gate != "" && !types.IsValidWaitsForGate(edge.Gate) {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Correct to_key to an existing node key in the plan
  2. Add the missing target node to plan.nodes
  3. Remove the stale edge, or use to_id referencing a real issue id

Example fix

// before
{"edges": [{"from_key": "build", "to_key": "depoy"}]}
// after
{"edges": [{"from_key": "build", "to_key": "deploy"}]}
Defensive patterns

Strategy: validation

Validate before calling

keys := map[string]bool{}
for _, n := range plan.Nodes { keys[n.Key] = true }
for i, e := range plan.Edges {
	if e.ToKey != "" && !keys[e.ToKey] { return fmt.Errorf("edge %d: unknown to_key %s", i, e.ToKey) }
}

Try / catch

if err := bd.GraphApply(ctx, plan, opts); err != nil {
	if strings.Contains(err.Error(), "to key") && strings.Contains(err.Error(), "not found in plan") {
		// fix edge target and retry
	}
}

Prevention

When it happens

Trigger: `bd graph apply` with plan.edges[i].to_key naming a key absent from plan.nodes.

Common situations: Typos in to_key; the target node was deleted from the plan while its incoming edges remained; merging plans whose key namespaces differ.

Related errors


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