{"record":{"id":"de65ed88cb34a472","repo":"hashicorp/packer","slug":"self-reference-s","errorCode":null,"errorMessage":"Self reference: %s","messagePattern":"Self reference: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/dag/dag.go","lineNumber":50,"sourceCode":"\t// Look for cycles of more than 1 component\n\tvar err error\n\tcycles := g.Cycles()\n\tif len(cycles) > 0 {\n\t\tfor _, cycle := range cycles {\n\t\t\tcycleStr := make([]string, len(cycle))\n\t\t\tfor j, vertex := range cycle {\n\t\t\t\tcycleStr[j] = VertexName(vertex)\n\t\t\t}\n\n\t\t\terr = errors.Join(err, fmt.Errorf(\n\t\t\t\t\"Cycle: %s\", strings.Join(cycleStr, \", \")))\n\t\t}\n\t}\n\n\t// Look for cycles to self\n\tfor _, e := range g.Edges() {\n\t\tif e.Source() == e.Target() {\n\t\t\terr = errors.Join(err, fmt.Errorf(\n\t\t\t\t\"Self reference: %s\", VertexName(e.Source())))\n\t\t}\n\t}\n\n\treturn err\n}\n\n// Cycles reports any cycles between graph nodes.\n// Self-referencing nodes are not reported, and must be detected separately.\nfunc (g *AcyclicGraph) Cycles() [][]Vertex {\n\tvar cycles [][]Vertex\n\tfor _, cycle := range StronglyConnected(&g.Graph) {\n\t\tif len(cycle) > 1 {\n\t\t\tcycles = append(cycles, cycle)\n\t\t}\n\t}\n\treturn cycles\n}","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/internal/dag/dag.go#L32-L68","documentation":"Alongside multi-vertex cycle detection, Validate separately scans every edge for self-loops (e.Source() == e.Target()) and reports `Self reference: <vertex>`. A vertex that depends on itself cannot be scheduled, and is reported distinctly from the generic cycle message for easier diagnosis.","triggerScenarios":"buildPrereqsDAG (or a test like TestAcyclicGraphValidate_cycleSelf) adds an edge from a vertex to itself, e.g. a component whose prerequisite list contains its own name.","commonSituations":"A build component accidentally naming itself as a prerequisite; name-resolution matching a component to itself when building the prereq map; copy-paste of an edge line without changing the source vertex.","solutions":["Remove the self-edge: find where the vertex adds itself as a dependency and skip it (if src == dst, don't add)","Fix name resolution so a component's own name in its prereq list is ignored rather than turned into an edge","Dedupe the dependency list before constructing the graph"],"exampleFix":"// before\nfor _, dep := range deps(v) { g.Add(v, dep) } // dep may be v itself\n// after\nfor _, dep := range deps(v) {\n    if dep == v { continue }\n    g.Add(v, dep)\n}","handlingStrategy":"validation","validationCode":"for _, e := range g.Edges() {\n    if e.Source() == e.Target() {\n        return fmt.Errorf(\"self reference: %s\", dag.VertexName(e.Source()))\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := g.Validate(); err != nil {\n    if strings.Contains(err.Error(), \"Self reference:\") {\n        return fmt.Errorf(\"component depends on itself: %w\", err)\n    }\n    return err\n}","preventionTips":["Skip edges where src == dst when building the graph","Filter a component's own name out of its prerequisite list","Deduplicate dependency lists before adding edges","Add a unit test with a self-loop vertex to catch regressions"],"tags":["dag","self-reference","graph"],"backgroundTag":"dependency-cycle","analyzedSha":"eb36e3c3e48a036f3e8cc94087636ee72e1303c9","analyzedAt":"2026-09-05T13:20:43.127Z","contentChangedAt":"2026-09-05T13:20:43.127Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}