labstack/echo · error

binding to multipart.FileHeader struct is not supported, use

Error message

binding to multipart.FileHeader struct is not supported, use pointer to struct

What it means

Returned by isFieldMultipartFile when a struct field used for multipart file binding is of type multipart.FileHeader by value. Echo can only bind files to *multipart.FileHeader, []multipart.FileHeader, or []*multipart.FileHeader because with a value-type FileHeader there is no way to distinguish 'no file uploaded' from 'a file uploaded' — a zero-value FileHeader is indistinguishable from a real one. The pointer/slice forms allow a nil check.

Source

Thrown at bind.go:512

}

var (
	// NOT supported by bind as you can NOT check easily empty struct being actual file or not
	multipartFileHeaderType = reflect.TypeFor[multipart.FileHeader]()
	// supported by bind as you can check by nil value if file existed or not
	multipartFileHeaderPointerType      = reflect.TypeFor[*multipart.FileHeader]()
	multipartFileHeaderSliceType        = reflect.TypeFor[[]multipart.FileHeader]()
	multipartFileHeaderPointerSliceType = reflect.TypeFor[[]*multipart.FileHeader]()
)

func isFieldMultipartFile(field reflect.Type) (bool, error) {
	switch field {
	case multipartFileHeaderPointerType,
		multipartFileHeaderSliceType,
		multipartFileHeaderPointerSliceType:
		return true, nil
	case multipartFileHeaderType:
		return true, errors.New("binding to multipart.FileHeader struct is not supported, use pointer to struct")
	default:
		return false, nil
	}
}

func setMultipartFileHeaderTypes(structField reflect.Value, inputFieldName string, files map[string][]*multipart.FileHeader) bool {
	fileHeaders := files[inputFieldName]
	if len(fileHeaders) == 0 {
		return false
	}

	result := true
	switch structField.Type() {
	case multipartFileHeaderPointerSliceType:
		structField.Set(reflect.ValueOf(fileHeaders))
	case multipartFileHeaderSliceType:
		headers := make([]multipart.FileHeader, len(fileHeaders))
		for i, fileHeader := range fileHeaders {

View on GitHub (pinned to 05489dc173)

Solutions

  1. Change the field type to *multipart.FileHeader
  2. For multiple files use []*multipart.FileHeader or []multipart.FileHeader
  3. Alternatively retrieve the file directly with c.FormFile("file") which returns *multipart.FileHeader

Example fix

// before
type UploadForm struct {
    File multipart.FileHeader `form:"file"`
}

// after
type UploadForm struct {
    File *multipart.FileHeader `form:"file"`
}
Defensive patterns

Strategy: type-guard

Type guard

// Ensure multipart file fields use pointer types
func checkFileHeaderFields(rt reflect.Type) error {
    fhType := reflect.TypeFor[multipart.FileHeader]()
    for i := 0; i < rt.NumField(); i++ {
        f := rt.Field(i)
        if f.Type == fhType {
            return fmt.Errorf("field %s: use *multipart.FileHeader, not multipart.FileHeader", f.Name)
        }
    }
    return nil
}

Try / catch

if err := c.Bind(&req); err != nil {
    if strings.Contains(err.Error(), "use pointer to struct") {
        return echo.NewHTTPError(http.StatusBadRequest, "file field must use pointer type")
    }
    return err
}

Prevention

When it happens

Trigger: Defining type UploadForm struct{ File multipart.FileHeader `form:"file"` } and submitting a multipart/form-data request to a handler that calls c.Bind(&UploadForm{}).

Common situations: Following an outdated tutorial using multipart.FileHeader by value. Code generators producing non-pointer FileHeader fields.

Related errors


AI-assisted analysis of labstack/echo@05489dc173 (2026-08-04). Data as JSON: /data/errors/5b4b44cbe2574851.json. Report an issue: GitHub.