pulumi/pulumi · error
cycle found: %s
Error message
cycle found: %s
What it means
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.
Source
Thrown at pkg/cmd/pulumi/diag/diag.go:58
func FormatCyclicInstallError(
ctx context.Context, err packageinstallation.ErrorCyclicDependencies,
wd string,
) error {
cyclePath := make([]string, len(err.Cycle))
for i, n := range err.Cycle {
name := n.Name
if plugin.IsLocalPluginPath(ctx, n.Name) {
rel, err := filepath.Rel(wd, n.Name)
if err == nil {
name = rel
}
}
if n.Version != nil {
name += "@" + n.Version.String()
}
cyclePath[i] = name
}
return fmt.Errorf("cycle found: %s", strings.Join(cyclePath, " -> "))
}
View on GitHub (pinned to 793f7b2e16)
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
Example fix
// before pkgA@1.0.0 -> pkgB@2.0.0 -> pkgA@1.0.0 (cycle) // after require pkgB at >=2.1.0 which no longer depends on pkgA, or drop pkgA's dependency on pkgB
Defensive patterns
Strategy: try-catch
Validate before calling
// build the dependency graph and topologically sort before install // if topoSort throws on a node already in the current stack, you have a cycle
Type guard
function hasCycle(graph) { /* DFS with rec-stack; return the cycle path or null */ } Try / catch
try { install(deps) } catch (e) { if (e.message.startsWith('cycle found:')) { console.error('break one of:', e.message); } else throw e } Prevention
- Topologically validate the dependency graph before installing
- Avoid mutual dependencies between packages/plugins you author
- Version-pin edges in one direction only
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- resolving stack: %w
- %s can't be safely deleted because the following resources d
- could not order deletions: selected resources have cyclic or
- could not resolve template: %w
- snapshot has cyclic dependencies
AI-assisted analysis of pulumi/pulumi@793f7b2e16 (2026-08-31).
Data as JSON: /api/errors/5cd896e36d1bd938.
Report an issue: GitHub.