siyuan-note/siyuan · error

read form part [ ] file [ ] error

Error message

read form part [%s] file [%s] error: %s

What it means

After opening a multipart file part, the plugin server reads handler.Size bytes; if file.Read returns an error the read fails, the file handle is closed, and this wrapped error (part name, filename, cause) is returned instead of the file contents.

Solutions

  1. Inspect the wrapped cause and re-upload the file
  2. Fix the client to send accurate multipart part sizes and keep the connection open until upload completes
  3. Use chunked/resumable uploads for large files to avoid mid-read disconnects
Defensive patterns

Strategy: retry

Validate before calling

if (!file || file.size === 0) throw new Error('refusing to upload empty/unknown-size file');

Type guard

null

Try / catch

try { await uploadFile(form); } catch (e) { if (String(e).includes('read form part')) { await sleep(1000); await uploadFile(form); } else { throw e; } }

Prevention

When it happens

Trigger: Reading an uploaded file part fails mid-read - typically because the client disconnected while uploading, the declared Content-Length/size disagrees with actual data, or the temp file was removed during the request.

Common situations: Network interruption during large uploads, mismatched multipart part sizes from custom clients, or antivirus/cleanup tools deleting temp files.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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

Appendix: 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 nothing

View on GitHub (pinned to 9f775e8a12)