{"record":{"id":"4db5d36a8a80d833","repo":"alibaba/canal","slug":"failed-rows-rows","errorCode":null,"errorMessage":"Failed rows:{rows}","messagePattern":"Failed rows:(.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"client-adapter/tablestore/src/main/java/com/alibaba/otter/canal/client/adapter/tablestore/TablestoreAdapter.java","lineNumber":155,"sourceCode":"            for (Future<WriterResult> future : futureList) {\n                try {\n                    WriterResult result = future.get();\n                    List<WriterResult.RowChangeStatus> failedRows = result.getFailedRows();\n                    if (!CollectionUtils.isEmpty(failedRows)) {\n                        totalFailedRows.addAll(failedRows);\n                    }\n                } catch (InterruptedException e) {\n                    logger.info(\"InterruptedException\", e);\n                    Thread.currentThread().interrupt();\n                } catch (ExecutionException e) {\n                    throw new RuntimeException(e);\n                }\n            }\n\n            if (!CollectionUtils.isEmpty(totalFailedRows)) {\n                // 认为有失败的请求\n                List<String> msgs = totalFailedRows.stream().map(e -> buildErrorMsgForFailedRowChange(e)).collect(Collectors.toList());\n                throw new RuntimeException(\"Failed rows:\" + org.springframework.util.StringUtils.collectionToDelimitedString(msgs, \",\", \"[\", \"]\"));\n            }\n\n        } catch (Exception e) {\n            throw e;\n        }\n    }\n\n    /**\n     * 组装失败记录的信息\n     * @param rowChangeStatus\n     * @return\n     */\n    public static String buildErrorMsgForFailedRowChange(WriterResult.RowChangeStatus rowChangeStatus) {\n        StringBuilder sb = new StringBuilder(\"{Exception:\");\n        sb.append(rowChangeStatus.getException().getMessage()).append(\",Table:\")\n        .append(rowChangeStatus.getRowChange().getTableName()).append(\",PrimaryKey:\")\n        .append(\"{\").append(rowChangeStatus.getRowChange().getPrimaryKey().toString())\n        .append(\"}}\");","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/client-adapter/tablestore/src/main/java/com/alibaba/otter/canal/client/adapter/tablestore/TablestoreAdapter.java#L137-L173","documentation":"Thrown after the TablestoreAdapter flushes all writers and collects Future results, when one or more row writes failed (WriterResult.getFailedRows() is non-empty). The error message includes a delimited list of failure descriptions built from each RowChangeStatus. This indicates that the Table Store (OTS) write API rejected specific rows, not that the flush mechanism itself failed.","triggerScenarios":"Calling the sync/flush path where one or more async writes to Alibaba Tablestore (OTS) returned errors — common causes include primary key conflicts (duplicate PK), throughput exceeded (throttling), data type mismatches, row size limits exceeded, or transient network issues between canal and the OTS endpoint.","commonSituations":"OTS table provisioned throughput is too low for the binlog event rate; duplicate PK values from source data; column data types in OTS don't match the mapping; network latency or intermittent connectivity to the OTS endpoint; large rows exceeding OTS row size limits.","solutions":["Inspect the error message details for each failed row — they typically contain the OTS error code (e.g. OTSQuotaExhausted, OTSParameterInvalid, OTSRowOperationConflict).","If throttled, increase the OTS table's provisioned read/write capacity or enable auto-scaling.","If PK conflicts, verify source data uniqueness and the PK mapping configuration.","If data type mismatch, align the OTS table column types with the tablestore fieldType mapping in the config.","For transient errors, implement retry logic or a dead-letter queue for failed rows."],"exampleFix":"// increase OTS table throughput if throttled\n// via Alibaba Cloud console or CLI:\n// ots update-table --instance <name> --read-capacity 5000 --write-capacity 5000\n\n// also check mapping config fieldType alignment\ndbMapping:\n  targetColumns:\n    pk_col:\n      type: INTEGER","handlingStrategy":"retry","validationCode":"null","typeGuard":"null","tryCatchPattern":"// Retry with backoff for transient OTS write failures\nint maxRetries = 3;\nfor (int attempt = 1; attempt <= maxRetries; attempt++) {\n    try {\n        tablestoreAdapter.sync(dmls);\n        break;\n    } catch (RuntimeException e) {\n        if (e.getMessage() != null && e.getMessage().contains(\"Failed rows:\") && attempt < maxRetries) {\n            logger.warn(\"OTS write failed on attempt {}/{}, retrying...\", attempt, maxRetries);\n            Thread.sleep(attempt * 2000L);\n            continue;\n        }\n        throw e;\n    }\n}","preventionTips":["Provision OTS table throughput with headroom above peak binlog event rate.","Monitor OTS throttling metrics and set alerts before capacity is exhausted.","Implement a dead-letter mechanism to persist failed rows for later replay.","Validate data types between source and OTS table schema before enabling sync."],"tags":["tablestore-adapter","write-failure","ots-throttling","data-sync"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}