gin-gonic/gin · error · ErrConvertMapStringSlice
can not convert to map slices of strings
Error message
can not convert to map slices of strings
What it means
ErrConvertMapStringSlice is returned by setFormMap (binding/form_mapping.go:534) when the binding target is a map whose element kind is Slice but the concrete value is not exactly map[string][]string. Gin only knows how to copy form values into the canonical map[string][]string shape.
Source
Thrown at binding/form_mapping.go:26
"encoding"
"errors"
"fmt"
"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{}View on GitHub (pinned to 34dac209ff)
Solutions
- Declare the bind target as map[string][]string (the only slice-map shape Gin supports) and convert values yourself afterwards.
- Prefer a struct with typed slice fields (e.g. IDs []int `form:"ids"`) so Gin's per-element setWithProperType does the conversion.
- If you need a custom map type, build a map[string][]string, call MapFormWithTag into it, then copy into your custom map.
Example fix
// before
m := map[string][]int{}
c.ShouldBindWith(&m, binding.Query)
// after
raw := map[string][]string{}
c.ShouldBindWith(&raw, binding.Query)
// then convert raw into your typed map Defensive patterns
Strategy: type-guard
Validate before calling
var target any = map[string][]int{}
if reflect.TypeOf(target).Kind() == reflect.Map {
elem := reflect.TypeOf(target).Elem()
if elem.Kind() == reflect.Slice && elem != reflect.TypeOf([]string{}).Elem() {
// will fail; switch to map[string][]string or use a struct
}
} Type guard
func isFormMapStringSlice(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.ErrConvertMapStringSlice) {
// target was a non-canonical slice-map; bind into map[string][]string and convert
}
} Prevention
- Prefer structs with typed slice fields over typed maps for binding.
- If you must use a map, declare it as map[string][]string (or map[string]string).
- Document the canonical map shapes in your handler signatures.
When it happens
Trigger: Binding a request into a variable typed map[string][]<non-string> (e.g. map[string][]int, map[string][]MyType) and then calling c.ShouldBind / MapFormWithTag.
Common situations: Trying to reuse a typed map (map[string][]int) as the bind target instead of a struct; passing a custom map alias type that does not satisfy the concrete map[string][]string assertion.
Related errors
- can not convert to map of strings
- unknown type
- %s is not supported in the collection_format. (multi, csv, s
- %q is not valid value for %s
- invalid request
AI-assisted analysis of gin-gonic/gin@34dac209ff (2026-08-04).
Data as JSON: /data/errors/e36780b56ddb9ada.json.
Report an issue: GitHub.