containerd/containerd · error
unable to downgrade because shim version (%d) is lower than
Error message
unable to downgrade because shim version (%d) is lower than CurrentShimVersion (%d)
What it means
shim.Downgrade steps a shim's tracked version down (used in version-negotiation fall-back logic). It refuses when s.version is already below CurrentShimVersion (or at the floor), because decrementing further would represent a protocol version this containerd cannot reason about, so it returns this descriptive error.
Source
Thrown at core/runtime/v2/shim.go:516
func (s *shim) BootstrapResult() *bootapi.BootstrapResult {
return s.bootstrap
}
// ID of the shim/task
func (s *shim) ID() string {
return s.bundle.ID
}
func (s *shim) Endpoint() (string, int) {
return s.address, s.version
}
func (s *shim) Downgrade() error {
if s.version >= CurrentShimVersion {
s.version--
return nil
}
return fmt.Errorf("unable to downgrade because shim version (%d) is lower than CurrentShimVersion (%d)",
s.version, CurrentShimVersion)
}
func (s *shim) Namespace() string {
return s.bundle.Namespace
}
func (s *shim) Bundle() string {
return s.bundle.Path
}
func (s *shim) Client() any {
return s.client
}
// Close closes the underlying client connection.
func (s *shim) Close() error {
if ttrpcClient, ok := s.client.(*ttrpc.Client); ok {View on GitHub (pinned to 4246446a2b)
Solutions
- Do not call Downgrade once the shim's version is below CurrentShimVersion; check s.version first
- Treat the shim as operating at its advertised version and handle the older protocol, or restart with a compatible shim
- If the goal is negotiating down from a newer shim, ensure the initial version actually exceeded CurrentShimVersion before downgrading
Example fix
// before
if err := shim.Downgrade(); err != nil { return err }
// after
if shim.Version() >= CurrentShimVersion {
if err := shim.Downgrade(); err != nil { return err }
} Defensive patterns
Strategy: validation
Validate before calling
if shim.Version() >= CurrentShimVersion {
if err := shim.Downgrade(); err != nil { /* ... */ }
} Try / catch
if err := shim.Downgrade(); err != nil {
log.G(ctx).WithError(err).Debug("shim already at minimum protocol version; skipping downgrade")
} Prevention
- Track the shim version returned at handshake and guard downgrade logic with it
- Limit downgrade attempts to at most (version - minSupported) calls
- Treat Downgrade failure as informational in negotiation fallback paths
When it happens
Trigger: Calling Downgrade on a shim whose s.version < CurrentShimVersion (e.g. version already at 0, 1, or 2 while CurrentShimVersion is 3).
Common situations: Repeated Downgrade calls exhausting the version; a shim that reported an older protocol version during handshake then being asked to downgrade again.
Related errors
- no metrics received
- shim was started through the deprecated API but was built ag
- shim shutdown timeout
- ErrNoAddress
- unable to make connection: %w
AI-assisted analysis of containerd/containerd@4246446a2b (2026-09-02).
Data as JSON: /api/errors/89718087ae435c36.
Report an issue: GitHub.