vitessio/vitess · warning
failed to cleanly close cluster (id=%s): %w
Error message
failed to cleanly close cluster (id=%s): %w
What it means
cluster.Close aggregates cleanup errors from all registered closers (DB, Vtctld, topo pools, etc.) via an errors.Group, and if any closer failed it returns this wrapped aggregate error including the cluster id. The schema cache is only closed if all closers succeeded. It indicates one or more resources did not shut down cleanly.
Source
Thrown at go/vt/vtadmin/cluster/cluster.go:236
rec concurrency.AllErrorRecorder
)
// First, close any caches, which may have connections to DB or Vtctld
// (N.B. (andrew) when we have multiple caches, we can close them
// concurrently, like we do with the proxies).
rec.RecordError(c.schemaCache.Close())
for _, closer := range []io.Closer{c.DB, c.Vtctld} {
wg.Add(1)
go func(closer io.Closer) {
defer wg.Done()
rec.RecordError(closer.Close())
}(closer)
}
wg.Wait()
if rec.HasErrors() {
return fmt.Errorf("failed to cleanly close cluster (id=%s): %w", c.ID, rec.Error())
}
return c.schemaCache.Close()
}
// ToProto returns a value-copy protobuf equivalent of the cluster.
func (c Cluster) ToProto() *vtadminpb.Cluster {
return &vtadminpb.Cluster{
Id: c.ID,
Name: c.Name,
}
}
func buildPFlagSlice(flags map[string]string) []string {
args := make([]string, 0, len(flags))
for k, v := range flags {
// The k=v syntax is needed to account for negating boolean flags.
args = append(args, "--"+k+"="+v)View on GitHub (pinned to 01a25a7d17)
Solutions
- Inspect the joined error(s) to see which closer failed; it is usually safe to restart vtadmin after fixing the underlying connection issue
- Ensure in-flight requests are drained before Close
- Check network/topo health if closers repeatedly fail
Defensive patterns
Strategy: try-catch
Try / catch
err := cluster.Close(ctx)
if err != nil {
if strings.Contains(err.Error(), "failed to cleanly close cluster") {
log.Warn("cluster shutdown had cleanup errors; inspecting",
slog.Any("error", err), slog.String("cluster_id", cluster.ID))
// non-fatal in most shutdown paths; proceed after logging
return nil
}
return err
} Prevention
- Drain in-flight RPCs before closing the cluster
- Keep timeouts generous in Close's bounded context so closers aren't cut off
- Log and alert on repeated close errors; they often precede connection issues at startup
When it happens
Trigger: Calling cluster.Close (directly or via vtadmin shutdown) when one of the concurrent closer goroutines returns a non-nil error — e.g. gRPC connection Close error, topo pool close failure.
Common situations: Shutdown while RPCs are in flight; already-broken connections erroring on Close; underlying servers returning errors during connection teardown.
Related errors
- can't lock shard: SIGTERM received
- vreplication engine is closed
- work queue is not open
- preflight_mysqld_shutdown hook failed: %v
- mysqld_shutdown hook failed: %v
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/175db3e62b3a1fe4.
Report an issue: GitHub.