docker/compose · error
cycle found: %s
Error message
cycle found: %s
What it means
The dependency graph DFS (Graph.visit) found a cycle in depends_on (and other dependency edges) and reports the exact path, e.g. 'web -> api -> web'. Compose cannot determine startup order for cyclic dependencies and aborts before creating anything.
Source
Thrown at pkg/compose/dependencies.go:431
if !slices.Contains(discovered, vertex.Key) && !slices.Contains(finished, vertex.Key) {
var err error
discovered, finished, err = g.visit(vertex.Key, path, discovered, finished)
if err != nil {
return true, err
}
}
}
return false, nil
}
func (g *Graph) visit(key string, path []string, discovered []string, finished []string) ([]string, []string, error) {
discovered = append(discovered, key)
for _, v := range g.Vertices[key].Children {
path := append(path, v.Key)
if slices.Contains(discovered, v.Key) {
return nil, nil, fmt.Errorf("cycle found: %s", strings.Join(path, " -> "))
}
if !slices.Contains(finished, v.Key) {
if _, _, err := g.visit(v.Key, path, discovered, finished); err != nil {
return nil, nil, err
}
}
}
discovered = slices.DeleteFunc(discovered, func(s string) bool { return s == key })
finished = append(finished, key)
return discovered, finished, nil
}
View on GitHub (pinned to ddc4b044b6)
Solutions
- Break the loop: make one direction optional (required: false) or drop it
- Restructure so shared prerequisites are a third service both depend on
- For mutual readiness, use healthchecks + restart-on-failure instead of circular depends_on
- docker compose config and inspect depends_on blocks to spot the back-edge
Example fix
# before
services:
a:
depends_on: [b]
b:
depends_on: [a]
# after
services:
a:
depends_on: [b]
b: {} Defensive patterns
Strategy: validation
Validate before calling
// DFS cycle check over depends_on before calling compose
var visit func(string, map[string]bool) error
visit = func(n string, seen map[string]bool) error {
if seen[n] { return fmt.Errorf("cycle at %s", n) }
seen[n] = true
for dep := range project.Services[n].DependsOn {
if err := visit(dep, seen); err != nil { return err }
}
delete(seen, n)
return nil
}
for n := range project.Services { if err := visit(n, map[string]bool{}); err != nil { return err } } Prevention
- Model readiness with healthchecks, not mutual depends_on
- Add a compose-file linter rule for dependency cycles in CI
- Keep dependency direction one-way (infra <- app)
When it happens
Trigger: Service A depends_on B while B depends_on A; longer loops a->b->c->a; also cycles introduced via multiple edges (depends_on plus other implicit deps) during HasCycles after graph build.
Common situations: Two services each waiting on the other (db healthcheck gating app while app is db's dependency); refactoring that inverts a dependency accidentally; healthcheck condition loops.
Related errors
- service %s is required by %s but is disabled. Can be enabled
- could not find %s: %w
- cannot publish compose file with local includes
- use_api_socket can't be used with a Windows Docker Engine
- healthcheck.start_interval requires healthcheck.start_period
AI-assisted analysis of docker/compose@ddc4b044b6 (2026-08-15).
Data as JSON: /api/errors/497c8c05f8dbdcac.
Report an issue: GitHub.