siyuan-note/siyuan · error
read form part [%s] file [%s] error: %s
Error message
read form part [%s] file [%s] error: %s
What it means
Returned by the plugin server's multipart parser after handler.Open() succeeded but file.Read(content) failed while reading an uploaded file's bytes into a buffer of handler.Size. Identifies part name and filename; aborts the whole form parse.
Source
Thrown at kernel/plugin/server.go:334
for partName, fileHandlers := range multipartForm.File {
files := make([]*RequestFile, len(fileHandlers))
form.File[partName] = files
for i, handler := range fileHandlers {
files[i] = &RequestFile{
Filename: handler.Filename,
Headers: handler.Header,
Size: handler.Size,
}
file, openErr := handler.Open()
if openErr != nil {
err = fmt.Errorf("open form part [%s] file [%s] error: %s", partName, handler.Filename, openErr.Error())
return
}
content := make([]byte, handler.Size)
n, readErr := file.Read(content)
file.Close()
if readErr != nil {
err = fmt.Errorf("read form part [%s] file [%s] error: %s", partName, handler.Filename, readErr.Error())
return
}
fileData := content[:n]
files[i].Data = &fileData
}
}
} else if len(c.Request.PostForm) > 0 {
// application/x-www-form-urlencoded
form = &RequestForm{
Value: c.Request.PostForm,
File: nil,
}
}
if form == nil {
// Not a form request, read raw body data
if rawData, readErr := c.GetRawData(); readErr != nil {
// request don't have body, do nothingView on GitHub (pinned to 251596fc0d)
Solutions
- Handle partial reads: use io.ReadAll or loop file.Read until EOF rather than a single Read of handler.Size.
- Validate Content-Length / declared size against actual bytes before allocating.
- If client disconnects are common, return a clear 4xx and let the client retry.
Example fix
// before content := make([]byte, handler.Size) n, readErr := file.Read(content) // after content, readErr := io.ReadAll(io.LimitReader(file, maxUploadBytes))
Defensive patterns
Strategy: try-catch
Validate before calling
// Validate declared size before allocating the read buffer.
function validateUploadSize(declared: number, max: number): void {
if (declared <= 0) throw new Error('invalid declared size')
if (declared > max) throw new Error('upload exceeds max size')
} Try / catch
// Robust read: loop or io.ReadAll, tolerate short reads and EOF.
buf := make([]byte, 0, handler.Size)
tmp := make([]byte, 32*1024)
for {
n, err := file.Read(tmp)
buf = append(buf, tmp[:n]...)
if err == io.EOF { break }
if err != nil { return err }
} Prevention
- Read with io.ReadAll / loop until EOF; do not rely on a single Read of declared size.
- Cap upload size with io.LimitReader to bound memory.
- Treat client disconnects during upload as expected, return 4xx.
When it happens
Trigger: Reading the opened multipart file part fails — short read, stream corruption, client disconnect mid-upload, or handler.Size mismatched actual bytes. content is allocated as make([]byte, handler.Size); a read error before that many bytes triggers it.
Common situations: Client disconnects during upload; Content-Length lies about size; network reset; the multipart part is larger/smaller than declared and io.Reader returns an error; very large file exhausting buffers.
Related errors
- open form part [%s] file [%s] error: %s
- Agent capability name and description are required
- ${data.error.message}
- no file found
- field [file] or [url] must not be empty
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/aeb023503ba36494.
Report an issue: GitHub.