argoproj/argo-workflows · error
invalid dependency %s
Error message
invalid dependency %s
What it means
During dependency registration, TopologicalSorting verifies each dependency string refers to a node already present in the graph (by NodeName). A dependency naming a node that was never added is rejected, since the sort cannot order against a nonexistent vertex.
Source
Thrown at util/sorting/topological_sorting.go:26
NodeName string
Dependencies []string
}
func TopologicalSorting(graph []*TopologicalSortingNode) ([]*TopologicalSortingNode, error) {
priorNodeCountMap := make(map[string]int, len(graph)) // nodeName -> priorNodeCount
nextNodeMap := make(map[string][]string, len(graph)) // nodeName -> nextNodeList
nodeNameMap := make(map[string]*TopologicalSortingNode, len(graph)) // nodeName -> node
for _, node := range graph {
if _, ok := nodeNameMap[node.NodeName]; ok {
return nil, fmt.Errorf("duplicated nodeName %s", node.NodeName)
}
nodeNameMap[node.NodeName] = node
priorNodeCountMap[node.NodeName] = len(node.Dependencies)
}
for _, node := range graph {
for _, dependency := range node.Dependencies {
if _, ok := nodeNameMap[dependency]; !ok {
return nil, fmt.Errorf("invalid dependency %s", dependency)
}
nextNodeMap[dependency] = append(nextNodeMap[dependency], node.NodeName)
}
}
queue := make([]*TopologicalSortingNode, len(graph))
head, tail := 0, 0
for nodeName, priorNodeCount := range priorNodeCountMap {
if priorNodeCount == 0 {
queue[tail] = nodeNameMap[nodeName]
tail++
}
}
for head < len(queue) {
curr := queue[head]
if curr == nil {
return nil, fmt.Errorf("graph with cycle")View on GitHub (pinned to 35bff19146)
Solutions
- Ensure every string in Dependencies matches exactly one node's NodeName in the same graph slice.
- When filtering nodes out of the graph, also remove/redirect their dependents' dependency references.
- Use the same name-building helper for both NodeName and Dependencies so they cannot diverge.
- Fix the test fixture to include the referenced dependency node.
Example fix
// before
graph = append(graph, &sorting.TopologicalSortingNode{NodeName: "B", Dependencies: []string{"A"}})
// after: node A must also be in the graph
graph = append(graph, &sorting.TopologicalSortingNode{NodeName: "A"},
&sorting.TopologicalSortingNode{NodeName: "B", Dependencies: []string{"A"}}) Defensive patterns
Strategy: validation
Validate before calling
func allDepsResolve(graph []*sorting.TopologicalSortingNode) error {
names := map[string]bool{}
for _, n := range graph { names[n.NodeName] = true }
for _, n := range graph {
for _, d := range n.Dependencies {
if !names[d] { return fmt.Errorf("dep %q missing from graph", d) }
}
}
return nil
} Try / catch
if err := allDepsResolve(graph); err != nil { return err }
sorted, err := sorting.TopologicalSorting(graph)
if err != nil { return fmt.Errorf("topological sort failed: %w", err) } Prevention
- Generate Dependencies from the same data structure that generates NodeNames so they can never diverge.
- When filtering the graph, filter dependency references in the same pass.
- Assert dependency closure in unit tests for any code building sort graphs.
When it happens
Trigger: A TopologicalSortingNode lists a Dependency whose name is not any node's NodeName — e.g. typos, dependency added for a node that was filtered out of the graph, or boundary/exit nodes referenced without being appended.
Common situations: Constructing the graph from DAG templates where an 'outbound' synchronization node is referenced but never inserted; renaming node names in one place but not in Dependencies; pruning failed steps from the graph while leaving their dependents' references; test fixtures with dangling dependencies.
Related errors
- duplicated nodeName %s
- graph with cycle
- successCondition, failureCondition and outputs are not suppo
- duration has to be positive, current duration: %v
- containers must have at least one container
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/4b6d4aef3f7315b7.
Report an issue: GitHub.