risingwavelabs/risingwave · error · SinkError::DorisStarrocksConnect

Can't get label from response

Error message

Can't get label from response

What it means

After a successful-status Starrocks transaction response is parsed, the optional 'label' field is absent, so the sink cannot return the transaction label. This indicates a malformed or unexpected success response from Starrocks.

Solutions

  1. Log the raw response body to confirm what Starrocks actually returned
  2. Upgrade or pin a Starrocks version whose insert/transaction API returns the label field
  3. Check for proxies or gateways between RisingWave and Starrocks that may rewrite responses
  4. Retry the transaction; if persistent, capture a curl of the same endpoint to compare

Example fix

// before
res.label.ok_or_else(|| SinkError::DorisStarrocksConnect(anyhow::anyhow!("Can't get label from response")))
// after
// include raw body for debugging
res.label.ok_or_else(|| SinkError::DorisStarrocksConnect(anyhow::anyhow!("Can't get label from response: {}", String::from_utf8_lossy(&raw))))
Defensive patterns

Strategy: try-catch

Validate before calling

if (!body || !('label' in body)) throw new Error('response missing label')

Type guard

const hasLabel = (r) => typeof r?.label === 'string' && r.label.length > 0;

Try / catch

catch (SinkError::DorisStarrocksConnect(e)) { dump raw response; alert on format drift }

Prevention

When it happens

Trigger: Starrocks FE responds with a success status but omits the 'label' field in the JSON body of begin/commit responses.

Common situations: Starrocks version with different response format; proxy/load-balancer stripping or altering the response body; FE misconfiguration.

Related errors


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

Appendix: source

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

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)
    }

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

View on GitHub (pinned to 6469eb736d)