siyuan-note/siyuan · error

unsupported multipart field

Error message

unsupported multipart field: %s

What it means

DecodeMultipart only knows how to map file parts (*multipart.FileHeader / slice) and string / *string parts; any struct field of another type hits the default branch and fails with this error. The request struct's field types must be restricted to the supported set, since multipart form values are strings and file headers only.

Solutions

  1. Change the field type to string (or *string) in the request struct and convert/parse it in the business handler.
  2. Remove the field from the struct if it is not actually part of the form.
  3. Handle the raw form via the MultipartFields request type if you need arbitrary access to values.

Example fix

// before
type req struct {
  Count int `api:"count"`
}
// after
type req struct {
  Count string `api:"count"` // strconv.Atoi in handler
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Go: ensure multipart struct fields are only string, *string, *multipart.FileHeader, or []*multipart.FileHeader
for _, f := range reflect.TypeOf(Req{}).Fields() { _ = f }

Type guard

func multipartFieldTypeOk(t reflect.Type) bool { return t == reflect.TypeFor[string]() || t == reflect.TypeFor[*string]() || t == reflect.TypeFor[*multipart.FileHeader]() || t == reflect.TypeFor[[]*multipart.FileHeader]() }

Try / catch

if err := decode(form); err != nil && strings.Contains(err.Error(), "unsupported multipart field") { log.Fatalf("unsupported field type in request struct: %v", err) }

Prevention

When it happens

Trigger: A multipart endpoint's request struct contains a field of an unsupported type, e.g. int, bool, []string, time.Time, or a custom struct, carrying an `api` form tag.

Common situations: Developer adds a numeric or boolean convenience field to an existing multipart request struct without realizing only strings/files are supported; code generation produced a typed field from a schema that assumed JSON bodies.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/da13b456b90ac2b0. Report an issue: GitHub.

Appendix: source

Thrown at kernel/apicontract/multipart.go:98

				value.Field(i).Set(reflect.ValueOf(files[0]))
			}
		case reflect.TypeFor[string](), reflect.TypeFor[*string]():
			values := form.Value[name]
			if len(values) == 0 {
				if !optional {
					return request, fmt.Errorf("Field [%s] is required", name)
				}
				continue
			}
			if field.Type.Kind() == reflect.Pointer {
				text := reflect.New(field.Type.Elem())
				text.Elem().SetString(values[0])
				value.Field(i).Set(text)
			} else {
				value.Field(i).SetString(values[0])
			}
		default:
			return request, fmt.Errorf("unsupported multipart field: %s", name)
		}
	}
	return
}

View on GitHub (pinned to 9f775e8a12)