windmill-labs/windmill · warning · std::io::Error

err (multipart field stream error converted to io::Error dur

Error message

err (multipart field stream error converted to io::Error during file upload)

What it means

In `process_multipart`, an uploaded file's multipart field is consumed as a byte stream and piped into object storage. Any error yielded by the multipart field stream (malformed part, client disconnect mid-upload, decoder failure) is mapped into a `std::io::Error` of kind `Other` carrying the original error's string, and that io error then fails the upload request. The original reqwest/axum multipart error type is erased by the wrapping.

Source

Thrown at backend/windmill-api/src/args.rs:184

                        let file_key = get_random_file_name(ext);

                        let options = Attributes::from_iter(vec![
                            (Attribute::ContentType, content_type),
                            (
                                Attribute::ContentDisposition,
                                if let Some(filename) = filename {
                                    format!("inline; filename=\"{}\"", filename)
                                } else {
                                    "inline".to_string()
                                },
                            ),
                        ])
                        .into();

                        let bytes_stream = field
                            .into_stream()
                            .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err));

                        // file_key is always freshly random here, so this never
                        // overwrites an existing object; the full size is the delta.
                        #[cfg(not(feature = "enterprise"))]
                        let max_size =
                            Some(ce_storage_quota_remaining(db, w_id, None).await? as usize);
                        #[cfg(feature = "enterprise")]
                        let max_size: Option<usize> = None;

                        match upload_file_internal(
                            s3_client.clone(),
                            &file_key,
                            bytes_stream,
                            options,
                            max_size,
                        )
                        .await
                        {

View on GitHub (pinned to e474e8803c)

Solutions

  1. Retry the upload from the client once the connection is stable; the error is usually a transient transport failure
  2. Read the wrapped message inside the io error for the underlying multipart failure cause
  3. Check intermediary proxies/timeouts for large uploads and raise body size/timeout limits
  4. Test the upload with a standard client (curl/browser) to rule out malformed multipart encoding
Defensive patterns

Strategy: retry

Try / catch

try {
  await uploadMultipart(file);
} catch (e) {
  if (e instanceof Error && /multipart|stream/i.test(e.message)) {
    // transient transport failure — retry upload from the start
  }
}

Prevention

When it happens

Trigger: A client aborts or resets the connection while streaming a file upload, the multipart body is truncated or malformed, or the field decoder errors partway through `field.into_stream()`.

Common situations: Large file uploads over flaky networks, browser cancellations, proxies cutting long uploads, malformed multipart boundaries from custom clients.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/a41d8d8d5ada7d4f. Report an issue: GitHub.