k3s-io/k3s · error

value required for kubelet-arg --%s

Error message

value required for kubelet-arg --%s

What it means

When starting the agent, k3s parses each --kubelet-arg value as either key=val or key followed by the value in the next list element. The keys `config` and `config-dir` are special-cased (k3s copies the referenced kubelet config into its managed dir), and they must carry a non-empty value. A bare or empty-valued `config`/`config-dir` entry aborts agent startup.

Source

Thrown at pkg/daemons/agent/agent.go:128

			continue
		}

		var val string
		key := strings.TrimPrefix(extraArgs[i], "--")
		if k, v, ok := strings.Cut(key, "="); ok {
			// key=val pair
			key = k
			val = v
		} else if len(extraArgs) > i+1 {
			// key in this arg, value in next arg
			val = extraArgs[i+1]
			skipVal = true
		}

		switch key {
		case "config", "config-dir":
			if val == "" {
				return nil, fmt.Errorf("value required for kubelet-arg --%s", key)
			}
			strippedArgs[key] = val
		default:
			args = append(args, extraArgs[i])
		}
	}

	// copy the config file into our managed config dir, unless its already in there
	if strippedArgs["config"] != "" && !strings.HasPrefix(strippedArgs["config"], path) {
		src := strippedArgs["config"]
		dest := filepath.Join(path, "10-cli-config.conf")
		if err := agentutil.CopyFile(src, dest, false); err != nil {
			return nil, errors.WithMessagef(err, "copy config %q into managed drop-in dir %q", src, dest)
		}
	}
	// copy the config-dir into our managed config dir, unless its already in there
	if strippedArgs["config-dir"] != "" && !strings.HasPrefix(strippedArgs["config-dir"], path) {
		src := strippedArgs["config-dir"]

View on GitHub (pinned to 6ba341e396)

Solutions

  1. Provide the value: `--kubelet-arg config=/etc/kubernetes/kubelet-config.yaml` (or the key item followed by its value item).
  2. Remove the bare `config`/`config-dir` entry entirely if no override is wanted - k3s generates its own kubelet config.
  3. Check the YAML config quoting: write kubelet-arg entries as complete strings like "config=/path", not split items.

Example fix

# before
k3s agent --server https://server:6443 --kubelet-arg config
# (or in /etc/rancher/k3s/config.yaml: kubelet-arg: ["config"])

# after
k3s agent --server https://server:6443 --kubelet-arg config=/etc/kubernetes/kubelet-config.yaml
Defensive patterns

Strategy: validation

Validate before calling

// Validate kubelet-arg entries before launching the agent:
func validateKubeletArgs(args []string) error {
    for i := 0; i < len(args); i++ {
        key, val, _ := strings.Cut(args[i], "=")
        if val == "" && len(args) > i+1 { val = args[i+1] }
        if (key == "config" || key == "config-dir") && strings.TrimSpace(val) == "" {
            return fmt.Errorf("kubelet-arg %q needs a value", key)
        }
    }
    return nil
}

Prevention

When it happens

Trigger: `--kubelet-arg config` as the last item in the list (no next element to use as value), `--kubelet-arg config=`, or a YAML config with `kubelet-arg: ["config"]` / `kubelet-arg: ["config="]` (pkg/daemons/agent/agent.go:120-130).

Common situations: Operator intends to point kubelet at a custom config file but forgets the value; YAML list item written with wrong quoting so the `=` part is lost; trailing empty element from a template.

Related errors


AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15). Data as JSON: /api/errors/860f7bf029d92202. Report an issue: GitHub.