{"record":{"id":"4b6d4aef3f7315b7","repo":"argoproj/argo-workflows","slug":"invalid-dependency-s","errorCode":null,"errorMessage":"invalid dependency %s","messagePattern":"invalid dependency (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/sorting/topological_sorting.go","lineNumber":26,"sourceCode":"\tNodeName     string\n\tDependencies []string\n}\n\nfunc TopologicalSorting(graph []*TopologicalSortingNode) ([]*TopologicalSortingNode, error) {\n\tpriorNodeCountMap := make(map[string]int, len(graph))               // nodeName -> priorNodeCount\n\tnextNodeMap := make(map[string][]string, len(graph))                // nodeName -> nextNodeList\n\tnodeNameMap := make(map[string]*TopologicalSortingNode, len(graph)) // nodeName -> node\n\tfor _, node := range graph {\n\t\tif _, ok := nodeNameMap[node.NodeName]; ok {\n\t\t\treturn nil, fmt.Errorf(\"duplicated nodeName %s\", node.NodeName)\n\t\t}\n\t\tnodeNameMap[node.NodeName] = node\n\t\tpriorNodeCountMap[node.NodeName] = len(node.Dependencies)\n\t}\n\tfor _, node := range graph {\n\t\tfor _, dependency := range node.Dependencies {\n\t\t\tif _, ok := nodeNameMap[dependency]; !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid dependency %s\", dependency)\n\t\t\t}\n\t\t\tnextNodeMap[dependency] = append(nextNodeMap[dependency], node.NodeName)\n\t\t}\n\t}\n\n\tqueue := make([]*TopologicalSortingNode, len(graph))\n\thead, tail := 0, 0\n\tfor nodeName, priorNodeCount := range priorNodeCountMap {\n\t\tif priorNodeCount == 0 {\n\t\t\tqueue[tail] = nodeNameMap[nodeName]\n\t\t\ttail++\n\t\t}\n\t}\n\n\tfor head < len(queue) {\n\t\tcurr := queue[head]\n\t\tif curr == nil {\n\t\t\treturn nil, fmt.Errorf(\"graph with cycle\")","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/util/sorting/topological_sorting.go#L8-L44","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ngraph = append(graph, &sorting.TopologicalSortingNode{NodeName: \"B\", Dependencies: []string{\"A\"}})\n// after: node A must also be in the graph\ngraph = append(graph, &sorting.TopologicalSortingNode{NodeName: \"A\"},\n    &sorting.TopologicalSortingNode{NodeName: \"B\", Dependencies: []string{\"A\"}})","handlingStrategy":"validation","validationCode":"func allDepsResolve(graph []*sorting.TopologicalSortingNode) error {\n    names := map[string]bool{}\n    for _, n := range graph { names[n.NodeName] = true }\n    for _, n := range graph {\n        for _, d := range n.Dependencies {\n            if !names[d] { return fmt.Errorf(\"dep %q missing from graph\", d) }\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := allDepsResolve(graph); err != nil { return err }\nsorted, err := sorting.TopologicalSorting(graph)\nif err != nil { return fmt.Errorf(\"topological sort failed: %w\", err) }","preventionTips":["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."],"tags":["go","dag","topological-sort","validation"],"backgroundTag":"missing-dependency-node","analyzedSha":"35bff19146f5a6ada77468c431f2624bd577e373","analyzedAt":"2026-09-03T19:34:35.908Z","contentChangedAt":"2026-09-03T19:34:35.908Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}