siyuan-note/siyuan · error
not found
Error message
%s not found
What it means
When mapping multipart form parts onto the request struct, a field typed *multipart.FileHeader (or a slice of them) must be present in form.File under its api tag name unless the tag includes ,optional,. If the named file part is absent, decoding fails with "<name> not found". It enforces required file uploads at the contract layer.
Solutions
- Append the file to FormData under the exact field name from the endpoint's request struct `api` tag.
- If the file is genuinely optional, mark the struct field's api tag as `api:"name,optional"`.
- Check server logs / the contract definition to confirm the expected field name, then align the client.
Example fix
// before
formData.append("upload", fileObj) // struct expects "file"
// after
formData.append("file", fileObj) Defensive patterns
Strategy: validation
Validate before calling
function requireFile(formData, name) {
const f = formData.get(name);
if (f == null || typeof f === "string") throw new Error("file part '" + name + "' is required");
} Type guard
const isUploadedFile = (v) => v != null && typeof v !== "string"; // File/Blob in browser
Try / catch
try { await upload(url, formData); } catch (e) { if (String(e).includes("not found")) { throw new Error("missing required file part — check field name matches the api tag"); } throw e; } Prevention
- Keep client FormData field names identical to the server struct's api tags.
- Mark truly optional file fields with ,optional, in the api tag.
- Check the file input is non-empty before submitting.
When it happens
Trigger: POSTing to a multipart endpoint without appending a file under the exact field name declared by the struct's `api` tag (e.g. the struct requires "file" but the client sent "upload").
Common situations: Client uses a different form field name than the contract; file input left empty in the UI; contract changed the field name while the client still uses the old one.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Field [ ] is required
- no file found
- open form part [ ] file [ ] error
- read form part [ ] file [ ] error
- 106
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/fb8a715f13acc50e.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/apicontract/multipart.go:73
value.Set(reflect.ValueOf(MultipartFields{Value: form.Value, File: form.File}))
return
}
if value.Kind() != reflect.Struct {
return request, fmt.Errorf("multipart request must be a struct")
}
if err = validateMultipartRequest(value.Type()); err != nil {
return
}
for i := 0; i < value.NumField(); i++ {
field := value.Type().Field(i)
name := strings.Split(field.Tag.Get("json"), ",")[0]
optional := strings.Contains(","+field.Tag.Get("api")+",", ",optional,")
switch field.Type {
case reflect.TypeFor[*multipart.FileHeader](), reflect.TypeFor[[]*multipart.FileHeader]():
files := form.File[name]
if len(files) == 0 {
if !optional {
return request, fmt.Errorf("%s not found", name)
}
continue
}
if field.Type.Kind() == reflect.Slice {
value.Field(i).Set(reflect.ValueOf(files))
} else {
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())View on GitHub (pinned to 9f775e8a12)