gin-gonic/gin · error · ErrConvertToMapString

can not convert to map of strings

Error message

can not convert to map of strings

What it means

ErrConvertToMapString is returned by setFormMap (binding/form_mapping.go:543) when the bind target is a string-keyed map whose element kind is not Slice, but the concrete value fails the map[string]string type assertion. Gin can only write the last form value per key into map[string]string.

Source

Thrown at binding/form_mapping.go:29

	"maps"
	"mime/multipart"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin/codec/json"
	"github.com/gin-gonic/gin/internal/bytesconv"
)

var (
	errUnknownType = errors.New("unknown type")

	// ErrConvertMapStringSlice can not convert to map[string][]string
	ErrConvertMapStringSlice = errors.New("can not convert to map slices of strings")

	// ErrConvertToMapString can not convert to map[string]string
	ErrConvertToMapString = errors.New("can not convert to map of strings")
)

func mapURI(ptr any, m map[string][]string) error {
	return mapFormByTag(ptr, m, "uri")
}

func mapForm(ptr any, form map[string][]string) error {
	return mapFormByTag(ptr, form, "form")
}

func MapFormWithTag(ptr any, form map[string][]string, tag string) error {
	return mapFormByTag(ptr, form, tag)
}

var emptyField = reflect.StructField{}

func mapFormByTag(ptr any, form map[string][]string, tag string) error {
	// Check if ptr is a map

View on GitHub (pinned to 34dac209ff)

Solutions

  1. Use a plain map[string]string as the bind target (Gin will pick the last value for each key).
  2. Switch to a struct with typed fields so the per-field converters run.
  3. For named/aliased map types, bind into map[string]string first, then copy into your alias.

Example fix

// before
type Params map[string]string
p := Params{}
c.ShouldBindWith(&p, binding.Query)
// after
p := map[string][]string{}
c.ShouldBindWith(&p, binding.Query)
params := Params{}
for k, v := range p { params[k] = v[len(v)-1] }
Defensive patterns

Strategy: type-guard

Validate before calling

var target any = Params{}
if reflect.TypeOf(target).Kind() == reflect.Map &&
   reflect.TypeOf(target).Elem().Kind() != reflect.Slice &&
   reflect.TypeOf(target) != reflect.TypeOf(map[string]string{}) {
    // will fail; switch to map[string]string or a struct
}

Type guard

func isFormMapString(v any) bool {
    _, ok := v.(map[string]string)
    return ok
}

Try / catch

if err := c.ShouldBindWith(&m, binding.Form); err != nil {
    if errors.Is(err, binding.ErrConvertToMapString) {
        // typed/aliased string-map; bind into map[string]string then copy
    }
}

Prevention

When it happens

Trigger: Binding into a map whose value type is a non-string scalar (map[string]int, map[string]bool, map[string]time.Time) or a custom alias of map[string]string.

Common situations: Binding query params into a typed map (map[string]int) expecting automatic conversion; using a named type `type Params map[string]string` whose assertion to the predeclared map[string]string fails.

Related errors


AI-assisted analysis of gin-gonic/gin@34dac209ff (2026-08-04). Data as JSON: /data/errors/704c28c5462c6127.json. Report an issue: GitHub.