go-kratos/kratos · error
config: merge dst must be *map[string]interface{}, got %T
Error message
config: merge dst must be *map[string]interface{}, got %T What it means
config.defaultMerge requires the merge destination to be *map[string]interface{} so it can allocate a nil destination map in place; any other dynamic type fails this check. In practice it appears when a custom Merger (registered via the config merger option) forwards a wrongly-typed dst to the default merger, or internal merge APIs are called directly.
Source
Thrown at config/merge.go:8
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)
continueView on GitHub (pinned to 668db92c2c)
Solutions
- Pass the destination as *map[string]any (pointer), never a map value
- If you need different semantics, register a full custom Merger instead of partially reusing defaultMerge
- Convert unknown-shaped values with the package's convertMap before merging
Example fix
// before
var dst map[string]any
_ = defaultMerge(dst, src) // passed by value: merge dst must be *map[string]interface{}
// after
var dst map[string]any
_ = defaultMerge(&dst, src) Defensive patterns
Strategy: type-guard
Type guard
func isMergeableDst(dst any) bool {
_, ok := dst.(*map[string]any)
return ok
} Try / catch
if err := defaultMerge(dst, src); err != nil {
if strings.HasPrefix(err.Error(), "config: merge dst") {
dstMap := map[string]any{}
err = defaultMerge(&dstMap, src) // correct shape, retry once
}
if err != nil {
return err
}
} Prevention
- Always pass *map[string]any (pointer) as the merge destination
- Prefer the package's Merger option over hand-rolled merging
- Unit-test custom mergers with nil destination maps
When it happens
Trigger: defaultMerge invoked with dst of any type other than *map[string]any — e.g. a custom Merger passing a map by value, or an unrelated type, instead of a pointer to the map.
Common situations: Writing a custom merger to customize deep-merge behavior and delegating to the default with a reshaped dst; code copied from tests that call merge internals directly.
Related errors
- type assert to %v failed
- kubernetes Object not ConfigMap
- config: merge src must be map[string]interface{}, got %T
- unsupported key: %s format: %s
- key not found
AI-assisted analysis of go-kratos/kratos@668db92c2c (2026-08-16).
Data as JSON: /api/errors/02b756ef38556508.
Report an issue: GitHub.