{"record":{"id":"5cd896e36d1bd938","repo":"pulumi/pulumi","slug":"cycle-found-s","errorCode":null,"errorMessage":"cycle found: %s","messagePattern":"cycle found: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/cmd/pulumi/diag/diag.go","lineNumber":58,"sourceCode":"func FormatCyclicInstallError(\n\tctx context.Context, err packageinstallation.ErrorCyclicDependencies,\n\twd string,\n) error {\n\tcyclePath := make([]string, len(err.Cycle))\n\tfor i, n := range err.Cycle {\n\t\tname := n.Name\n\t\tif plugin.IsLocalPluginPath(ctx, n.Name) {\n\t\t\trel, err := filepath.Rel(wd, n.Name)\n\t\t\tif err == nil {\n\t\t\t\tname = rel\n\t\t\t}\n\t\t}\n\t\tif n.Version != nil {\n\t\t\tname += \"@\" + n.Version.String()\n\t\t}\n\t\tcyclePath[i] = name\n\t}\n\treturn fmt.Errorf(\"cycle found: %s\", strings.Join(cyclePath, \" -> \"))\n}\n","sourceCodeStart":40,"sourceCodeEnd":60,"githubUrl":"https://github.com/pulumi/pulumi/blob/793f7b2e160db4321fb7fb6b0607461e01cb251e/pkg/cmd/pulumi/diag/diag.go#L40-L60","documentation":"FormatCyclicInstallError formats a detected dependency cycle from an install/upgrade graph (e.g. plugin or package dependency nodes) into a single error listing the cycle path as node@version entries joined by ' -> '. The underlying cycle detection ran first; this error is the human-readable report.","triggerScenarios":"Installing or resolving components whose dependency graph contains a cycle, e.g. A depends on B and B depends on A (directly or through several hops).","commonSituations":"Hand-written plugin requirements that mutually reference each other; version pinning changes that introduce a round trip in the graph; publishing two packages each depending on the other.","solutions":["Inspect the printed cycle path and break the loop by removing one dependency edge","Pin different versions so the dependency is one-directional, or split the shared functionality into a third package","Regenerate/update the requirement or lock file after fixing the graph"],"exampleFix":"// before\npkgA@1.0.0 -> pkgB@2.0.0 -> pkgA@1.0.0  (cycle)\n// after\nrequire pkgB at >=2.1.0 which no longer depends on pkgA, or drop pkgA's dependency on pkgB","handlingStrategy":"try-catch","validationCode":"// build the dependency graph and topologically sort before install\n// if topoSort throws on a node already in the current stack, you have a cycle","typeGuard":"function hasCycle(graph) { /* DFS with rec-stack; return the cycle path or null */ }","tryCatchPattern":"try { install(deps) } catch (e) { if (e.message.startsWith('cycle found:')) { console.error('break one of:', e.message); } else throw e }","preventionTips":["Topologically validate the dependency graph before installing","Avoid mutual dependencies between packages/plugins you author","Version-pin edges in one direction only"],"tags":["dependency-graph","cycle","resolution"],"backgroundTag":"dependency-cycle","analyzedSha":"793f7b2e160db4321fb7fb6b0607461e01cb251e","analyzedAt":"2026-08-31T09:36:43.099Z","schemaVersion":2},"datasetVersion":"2026-09-01T08:17:40.651Z"}