kubernetes/kubernetes · error

failed to marshal base config: %w

Error message

failed to marshal base config: %w

What it means

Returned inside mergeKubeletConfigurations (cmd/kubelet/app/server.go:351) when json.Marshal of the versioned base KubeletConfiguration fails while preparing the base JSON for drop-in merging. Because KubeletConfiguration is a well-defined struct with marshalable field types, a marshal failure is effectively a programming/scheme-conversion error rather than a user config problem.

Source

Thrown at cmd/kubelet/app/server.go:351

// configurations in files with lower numeric prefixes are applied first, followed by higher numeric prefixes.
// For example, if the drop-in directory contains files named "10-config.conf" and "20-config.conf",
// the configurations in "10-config.conf" will be applied first, and then the configurations in "20-config.conf" will be applied,
// potentially overriding the previous values. Files in subdirectories are also processed in lexical order.
// Returns a list of skipped files and an error.
func mergeKubeletConfigurations(kubeletConfig *kubeletconfiginternal.KubeletConfiguration, kubeletDropInConfigDir string) ([]string, error) {
	const dropinFileExtension = ".conf"
	var skippedFiles []string

	// TODO: move the "internal --> versioned --> merge --> default --> internal" operation inside the loop,
	// and use the version of each drop-in file as the versioned target once config files can be in versions other than just v1beta1
	versionedConfig := &kubeletconfigv1beta1.KubeletConfiguration{}
	if err := kubeletconfigv1beta1conversion.Convert_config_KubeletConfiguration_To_v1beta1_KubeletConfiguration(kubeletConfig, versionedConfig, nil); err != nil {
		return nil, err
	}

	baseKubeletConfigJSON, err := json.Marshal(versionedConfig)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal base config: %w", err)
	}
	// Walk through the drop-in directory and update the configuration for each file
	if err := filepath.WalkDir(kubeletDropInConfigDir, func(path string, info fs.DirEntry, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		}
		if filepath.Ext(info.Name()) != dropinFileExtension {
			skippedFiles = append(skippedFiles, path)
			return nil
		}
		dropinConfigJSON, gvk, err := loadDropinConfigFileIntoJSON(path)
		if err != nil {
			return fmt.Errorf("failed to load kubelet dropin file, path: %s, error: %w", path, err)
		}
		if gvk == nil || gvk.Empty() {

View on GitHub (pinned to b882c60b40)

Solutions

  1. Confirm you are running an official, unmodified kubelet build for your Kubernetes version.
  2. Temporarily remove --config-dir to bypass the drop-in merge path and confirm startup proceeds.
  3. File a Kubernetes issue with the version and the wrapped marshal error, since this reflects a scheme/conversion defect.
Defensive patterns

Strategy: try-catch

Try / catch

skipped, err := mergeKubeletConfigurations(kubeletConfig, dropInDir)
if err != nil {
    if strings.Contains(err.Error(), "failed to marshal base config") {
        // scheme/conversion bug — report upstream, drop --config-dir to proceed
    }
    return err
}

Prevention

When it happens

Trigger: A field on the v1beta1 KubeletConfiguration that cannot be JSON-marshaled after the Convert_config_KubeletConfiguration_To_v1beta1 conversion — e.g. a channel/func type introduced by a bug, or a custom type lacking JSON support. Reached only when --config-dir is set.

Common situations: A kubelet build with a regression in the config scheme conversion; essentially never seen in released versions. If hit, it indicates a binary/scheme bug, not a configuration mistake.

Related errors


AI-assisted analysis of kubernetes/kubernetes@b882c60b40 (2026-08-07). Data as JSON: /api/errors/73454bfa91c675f3. Report an issue: GitHub.