go-kratos/kratos · error

config: merge src must be map[string]interface{}, got %T

Error message

config: merge src must be map[string]interface{}, got %T

What it means

The default config merger converts src via convertMap and requires the result to be map[string]interface{}; values that decode to slices, scalars, or other shapes fail this check. The root cause is almost always a config document whose top level is not a mapping (e.g. a YAML list or JSON array).

Source

Thrown at config/merge.go:12

package config

import "fmt"

func defaultMerge(dst, src any) error {
	dstMap, ok := dst.(*map[string]any)
	if !ok {
		return fmt.Errorf("config: merge dst must be *map[string]interface{}, got %T", dst)
	}
	srcMap, ok := convertMap(src).(map[string]any)
	if !ok {
		return fmt.Errorf("config: merge src must be map[string]interface{}, got %T", src)
	}
	if *dstMap == nil {
		*dstMap = make(map[string]any, len(srcMap))
	}
	mergeMap(*dstMap, srcMap)
	return nil
}

func mergeMap(dst, src map[string]any) {
	for key, srcValue := range src {
		if srcMap, ok := srcValue.(map[string]any); ok {
			if dstMap, ok := dst[key].(map[string]any); ok {
				mergeMap(dstMap, srcMap)
				continue
			}
		}
		dst[key] = cloneMergeValue(srcValue)
	}

View on GitHub (pinned to 668db92c2c)

Solutions

  1. Edit the config file so its top level is a mapping (YAML map / JSON object)
  2. Move lists under a named key: items: [ ... ]
  3. Validate locally before shipping: yaml.Unmarshal(file, &map[string]any) must succeed

Example fix

# before - config.yaml (top-level list)
- name: a
  port: 8000
- name: b
  port: 8001

# after
services:
  - name: a
    port: 8000
  - name: b
    port: 8001
Defensive patterns

Strategy: type-guard

Validate before calling

var probe any
if err := codec.Unmarshal(raw, &probe); err != nil {
    return err
}
if _, ok := probe.(map[string]any); !ok {
    return fmt.Errorf("config root must be a mapping, got %T", probe)
}

Type guard

func isMapConfig(v any) bool {
    switch v.(type) {
    case map[string]any, map[any]any:
        return true
    }
    return false
}

Prevention

When it happens

Trigger: A Source returns bytes that decode to a non-map root — YAML starting with a list item, a JSON array, or a bare scalar — so convertMap(src) cannot produce map[string]any during merge.

Common situations: A docker-compose-style YAML fragment reused as config; concatenated YAML documents; a values file that is a single scalar; hand-written JSON arrays at the root.

Related errors


AI-assisted analysis of go-kratos/kratos@668db92c2c (2026-08-16). Data as JSON: /api/errors/7df9d5c05782aa70. Report an issue: GitHub.