{"record":{"id":"538223ff89a701c3","repo":"risingwavelabs/risingwave","slug":"transaction-error","errorCode":null,"errorMessage":"transaction error: {}, {}, {:?}","messagePattern":"transaction error: (.+?), (.+?), (.+?)","errorType":"exception","errorClass":"SinkError::DorisStarrocksConnect","httpStatus":null,"severity":"error","filePath":"src/connector/src/sink/starrocks.rs","lineNumber":909,"sourceCode":"        };\n        Ok(res)\n    }\n}\n\npub struct StarrocksTxnClient {\n    request_builder: StarrocksTxnRequestBuilder,\n}\n\nimpl StarrocksTxnClient {\n    pub fn new(request_builder: StarrocksTxnRequestBuilder) -> Self {\n        Self { request_builder }\n    }\n\n    fn check_response_and_extract_label(&self, res: Bytes) -> Result<String> {\n        let res: StarrocksInsertResultResponse = serde_json::from_slice(&res)\n            .map_err(|err| SinkError::DorisStarrocksConnect(anyhow!(err)))?;\n        if !STARROCKS_SUCCESS_STATUS.contains(&res.status.as_str()) {\n            return Err(SinkError::DorisStarrocksConnect(anyhow::anyhow!(\n                \"transaction error: {}, {}, {:?}\",\n                res.status,\n                res.message,\n                res.error_url,\n            )));\n        }\n        res.label.ok_or_else(|| {\n            SinkError::DorisStarrocksConnect(anyhow::anyhow!(\"Can't get label from response\"))\n        })\n    }\n\n    pub async fn begin(&self, label: String) -> Result<String> {\n        let res = self\n            .request_builder\n            .build_begin_request_sender(label)?\n            .send()\n            .await?;\n        self.check_response_and_extract_label(res)","sourceCodeStart":891,"sourceCodeEnd":927,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/connector/src/sink/starrocks.rs#L891-L927","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Open res.error_url in a browser to read the detailed load error log from Starrocks","Check whether the transaction label was already used (label conflict) and use a unique label","Verify table schema and column mappings match the data being sent","Check Starrocks FE/BE logs and cluster health; retry the transaction once the cluster recovers"],"exampleFix":"// before\nreturn Err(SinkError::DorisStarrocksConnect(anyhow::anyhow!(\"transaction error: {}, {}, {:?}\", res.status, res.message, res.error_url)));\n// after\n// retry with a fresh unique label and inspect error_url for root cause\nlet new_label = format!(\"{}-retry-{}\", label, uuid::Uuid::new_v4());","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match result { Err(SinkError::DorisStarrocksConnect(e)) => { log error_url from e; retry with new label }, Ok(label) => proceed }","preventionTips":["Always use unique transaction labels (uuid suffix)","Inspect error_url promptly after failures","Monitor Starrocks cluster health before heavy loads"],"tags":["starrocks","sink","http-error-response","transaction"],"backgroundTag":"http-error-response","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}