kubernetes/kops · warning

error listing /etc/containerd: %v

Error message

error listing /etc/containerd: %v

What it means

Accumulated by logDumperNode.dump (pkg/dump/dumper.go:505) when n.findFiles(ctx, "/etc/containerd") fails. This step lists containerd configuration files (config.toml, CNI templates, certs.d hosts.toml) on the node so their .toml/.template files can be copied into the artifacts. The failure is logged as a warning and the rest of the dump proceeds without containerd configs.

Source

Thrown at pkg/dump/dumper.go:505

	if err := n.shellToFile(ctx, "cat /etc/hosts", filepath.Join(n.dir, "etchosts")); err != nil {
		errors = append(errors, err)
	}
	if err := n.shellToFile(ctx, "sysctl -a", filepath.Join(n.dir, "sysctls")); err != nil {
		errors = append(errors, err)
	}

	if err := n.shellToFile(ctx, "cat /var/lib/kubelet/kubelet.conf", filepath.Join(n.dir, "kubelet.conf")); err != nil {
		errors = append(errors, err)
	}

	if err := n.shellToFile(ctx, "cat /proc/modules", filepath.Join(n.dir, "modules")); err != nil {
		errors = append(errors, err)
	}

	// Capture containerd configuration files (config.toml, CNI templates, certs.d hosts.toml).
	containerdFiles, err := n.findFiles(ctx, "/etc/containerd")
	if err != nil {
		errors = append(errors, fmt.Errorf("error listing /etc/containerd: %v", err))
	}
	for _, f := range containerdFiles {
		if !strings.HasSuffix(f, ".toml") && !strings.HasSuffix(f, ".template") {
			continue
		}
		rel := strings.TrimPrefix(f, "/etc/containerd/")
		dest := filepath.Join(n.dir, "containerd", rel)
		cmd := "sudo cat '" + strings.ReplaceAll(f, "'", `'\''`) + "'"
		if err := n.shellToFile(ctx, cmd, dest); err != nil {
			errors = append(errors, err)
		}
	}

	return errors
}

// findFiles lists files under the specified directory (recursively)
func (n *logDumperNode) findFiles(ctx context.Context, dir string) ([]string, error) {

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Confirm the node actually uses containerd: `ssh <node> ls /etc/containerd`; on docker-runtime nodes this warning is expected and can be ignored.
  2. SSH in and run `sudo find /etc/containerd -type f -print0` to capture the real error (exit code, permissions).
  3. If the timeout is the cause, increase --node-dump-timeout.
  4. Re-run the dump if the failure was transient (session drop); the per-node dump is idempotent.
  5. Ensure sudo works non-interactively on the node (NOPASSWD) — a sudo password prompt over the piped session surfaces as a command failure.
Defensive patterns

Strategy: fallback

Validate before calling

// only list containerd config when containerd is in use
if err := client.ExecPiped(ctx, "test -d /etc/containerd", io.Discard, io.Discard); err != nil {
    klog.V(2).Infof("no /etc/containerd on node; skipping containerd config dump")
}

Try / catch

containerdFiles, err := n.findFiles(ctx, "/etc/containerd")
if err != nil {
    klog.Warningf("containerd config capture skipped: %v", err)
    containerdFiles = nil
}

Prevention

When it happens

Trigger: ExecPiped of `sudo find /etc/containerd -type f -print0` errors: the directory does not exist (docker-based or non-containerd node), find exits non-zero because of the missing path, the SSH session drops, or the nodeDumpTimeout context expires before the command completes.

Common situations: Clusters still using the docker runtime (pre-containerd kOps versions) or custom runtime layouts where /etc/containerd is absent; upgrading a cluster where some nodes run containerd and others do not; transient SSH failures mid-dump.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/cb3742c05f17dd90. Report an issue: GitHub.