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

  1. Do not call Downgrade once the shim's version is below CurrentShimVersion; check s.version first
  2. Treat the shim as operating at its advertised version and handle the older protocol, or restart with a compatible shim
  3. 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

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


AI-assisted analysis of containerd/containerd@4246446a2b (2026-09-02). Data as JSON: /api/errors/89718087ae435c36. Report an issue: GitHub.