risingwavelabs/risingwave · error · SinkError
Can't clone request
Error message
Can't clone request
What it means
`send_stream_load_request` manually follows FE redirects (to preserve Authorization headers that reqwest would strip) by cloning the outgoing request each round with `try_clone`. `Request::try_clone` returns None when the request body is not cloneable (a non-in-memory/streaming body), so cloning fails and this error is thrown.
Source
Thrown at src/connector/src/sink/doris_starrocks_connector.rs:418
/// The reason we handle the redirection manually is that if we let `reqwest` handle the redirection
/// automatically, it will remove sensitive headers (such as Authorization) during the redirection,
/// and there's no way to prevent this behavior.
/// Please note, the FE address that user specified might be a FE follower not the leader, in this case,
/// the follower FE will redirect request to leader FE and then to BE.
async fn send_stream_load_request(
client: Client,
mut request: Request,
fe_host: &str,
) -> Result<StreamLoadResponse> {
// possible redirection paths:
// RW <-> follower FE -> leader FE -> BE
// RW <-> leader FE -> BE
// RW <-> leader FE
for _ in 0..2 {
let original_http_port = request.url().port();
let mut request_for_redirection = request
.try_clone()
.ok_or_else(|| SinkError::DorisStarrocksConnect(anyhow!("Can't clone request")))?;
let resp = client.execute(request).await.map_err(|err| {
SinkError::DorisStarrocksConnect(
anyhow!(err).context("sending stream load request failed"),
)
})?;
let be_url = try_get_be_url(&resp, fe_host)?;
match be_url {
Some(be_url) => {
// we used an unconventional method to detect if we are currently redirecting to FE leader, i.e.,
// by comparing the port of the redirected url with that of the original request, if they are same, we consider
// this is a FE address. Because in practice, no one would deploy their `StarRocks` cluster with the same
// http port for both FE and BE. However, this is a potentially problematic assumption,
// we may investigate a better way to do this. For example, we could use the `show backends` command to check
// if the host of the redirected url is in the list. However, `show backends` requires
// the system-level privilege, which could break the backward compatibility.
let redirected_port = be_url.port();
*request_for_redirection.url_mut() = be_url;
if redirected_port == original_http_port {View on GitHub (pinned to 6469eb736d)
Solutions
- Ensure the request passed to `send_stream_load_request` has an in-memory body (`Bytes`/`&'static [u8]`), which reqwest can clone
- Refactor so the body is rebuilt from a buffer instead of relying on `try_clone` on a streaming body
- Check recent changes to request construction in `send`/`build_txn_inserter`; this is typically a code bug, not a user config issue
- As a workaround, reconstruct the request per redirect round using stored URL/headers/body instead of cloning
Example fix
// before: body built as a stream, try_clone returns None let request = client.put(url).body(Body::wrap_stream(stream)); // after: body buffered so the request is clonable let request = client.put(url).body(bytes); // Bytes: try_clone succeeds
Defensive patterns
Strategy: validation
Validate before calling
// ensure the request body is clonable before calling the send path assert!(matches!(body, reqwest::Body::Bytes(_) | reqwest::Body::Wrapper(_)) == false || !matches!(body, reqwest::Body::Stream(_)), "body must be buffered, not a stream");
Try / catch
let request = match request.try_clone() {
Some(cloned) => cloned,
None => return Err(rebuild_request_from_parts(&request)),
}; Prevention
- Always build stream-load request bodies from buffered Bytes so try_clone succeeds
- Add a unit test covering FE-follower -> FE-leader -> BE redirection
- Avoid wrapping request bodies in streams on this code path
When it happens
Trigger: `send_stream_load_request` is called (from `send` or `build_txn_inserter`) with a request whose body cannot be cloned — e.g. a streaming body rather than a fully-buffered `Bytes` body — on the first or redirect iteration.
Common situations: Upstream code change replaced a `Bytes` body with a stream; regression after refactor of how the txn/stream-load request body is constructed; attempting to reuse a request that already had its body consumed.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- `{}` must be {}, or {}
- Primary key not defined for upsert doris sink (please define
- If you want to use upsert, please set the keysType of doris
- Can't find data
- Insert error: {:?}, error url: {:?}
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/4fd2b33d34962784.
Report an issue: GitHub.