risingwavelabs/risingwave · error · SinkError::DorisStarrocksConnect

transaction error

Error message

transaction error: {}, {}, {:?}

What it means

When a Starrocks/RocksDB stream-load transaction returns a status not in STARROCKS_SUCCESS_STATUS, the sink wraps the full response (status, message, error_url) in a DorisStarrocksConnect error. It means the remote Starrocks FE rejected or failed the transaction (e.g. label conflict, load failure, internal error), not a local bug.

Solutions

  1. Open res.error_url in a browser to read the detailed load error log from Starrocks
  2. Check whether the transaction label was already used (label conflict) and use a unique label
  3. Verify table schema and column mappings match the data being sent
  4. Check Starrocks FE/BE logs and cluster health; retry the transaction once the cluster recovers

Example fix

// before
return Err(SinkError::DorisStarrocksConnect(anyhow::anyhow!("transaction error: {}, {}, {:?}", res.status, res.message, res.error_url)));
// after
// retry with a fresh unique label and inspect error_url for root cause
let new_label = format!("{}-retry-{}", label, uuid::Uuid::new_v4());
Defensive patterns

Strategy: retry

Try / catch

match result { Err(SinkError::DorisStarrocksConnect(e)) => { log error_url from e; retry with new label }, Ok(label) => proceed }

Prevention

When it happens

Trigger: Calling begin/commit/other transaction APIs on StarrocksSink when the JSON response body has a status field outside the success set (e.g. 'Fail', label already exists, FE overloaded).

Common situations: Duplicate transaction label from a retried commit; Starrocks FE returning error during load; cluster under pressure; wrong table/column mapping causing load rejection visible in error_url.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/538223ff89a701c3. Report an issue: GitHub.

Appendix: source

Thrown at src/connector/src/sink/starrocks.rs:909

        };
        Ok(res)
    }
}

pub struct StarrocksTxnClient {
    request_builder: StarrocksTxnRequestBuilder,
}

impl StarrocksTxnClient {
    pub fn new(request_builder: StarrocksTxnRequestBuilder) -> Self {
        Self { request_builder }
    }

    fn check_response_and_extract_label(&self, res: Bytes) -> Result<String> {
        let res: StarrocksInsertResultResponse = serde_json::from_slice(&res)
            .map_err(|err| SinkError::DorisStarrocksConnect(anyhow!(err)))?;
        if !STARROCKS_SUCCESS_STATUS.contains(&res.status.as_str()) {
            return Err(SinkError::DorisStarrocksConnect(anyhow::anyhow!(
                "transaction error: {}, {}, {:?}",
                res.status,
                res.message,
                res.error_url,
            )));
        }
        res.label.ok_or_else(|| {
            SinkError::DorisStarrocksConnect(anyhow::anyhow!("Can't get label from response"))
        })
    }

    pub async fn begin(&self, label: String) -> Result<String> {
        let res = self
            .request_builder
            .build_begin_request_sender(label)?
            .send()
            .await?;
        self.check_response_and_extract_label(res)

View on GitHub (pinned to 6469eb736d)