apache/seatunnel · error · RuntimeException

shard cursor error

Error message

shard cursor error

What it means

The SLS (Aliyun Log Service) source split enumerator builds a shard read cursor during split assignment and throws this if the resolved cursor string is empty. An empty cursor means the consumer position could not be resolved from the log service, so the split would read nothing or behave unpredictably.

Solutions

  1. Check that the logStore and shard contain data for the configured cursor mode (e.g. begin/end/timestamp).
  2. Verify cursorMode and autoCursorReset options are valid values supported by the SLS SDK.
  3. Ensure the SLS credentials (project, accessKey) allow GetCursor on the logstore.
  4. Add logging around initShardCursor to see which mode returned the empty cursor and retry with an explicit valid cursor mode.

Example fix

// before
if (cursor.equals("")) {
    throw new RuntimeException("shard cursor error");
}
// after
if (cursor == null || cursor.isEmpty()) {
    throw new IllegalStateException(
        "SLS returned an empty cursor for shard " + shardIdKey
        + " in logStore " + logStore + " with cursorMode " + cursorMode
        + "; verify the shard has readable data or set autoCursorReset appropriately");
}
Defensive patterns

Strategy: validation

Validate before calling

String cursor = initShardCursor(...); if (cursor == null || cursor.isEmpty()) { throw new IllegalStateException("empty SLS cursor for " + logStore + "/shard " + shardIdKey + ", cursorMode=" + cursorMode); }

Try / catch

try { enumerator.discoverySplits(); } catch (RuntimeException e) { if (String.valueOf(e.getMessage()).contains("shard cursor error")) { log.error("SLS shard cursor empty; check cursorMode/data", e); throw new ConfigurationException(...); } throw e; }

Prevention

When it happens

Trigger: fetchPendingShardSplit (called from discoverySplits) constructs a cursor via initShardCursor; if GetCursor succeeds through all cursor modes but the returned cursor string equals "", the RuntimeException is thrown.

Common situations: Empty logStore shards with no readable data for the requested cursor mode; misconfigured autoCursorReset values; logstore recently created/truncated so no cursor exists for the given mode.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/5207a2d5418c0a57. Report an issue: GitHub.

Appendix: source

Thrown at seatunnel-connectors-v2/connector-sls/src/main/java/org/apache/seatunnel/connectors/seatunnel/sls/source/SlsSourceSplitEnumerator.java:195

                .forEach(
                        shard -> {
                            if (!assignedSplit.containsKey(shard.getShardId())) {
                                if (!pendingSplit.containsKey(shard.getShardId())) {
                                    String cursor = "";
                                    try {
                                        cursor =
                                                initShardCursor(
                                                        project,
                                                        logStore,
                                                        consumer,
                                                        shard.getShardId(),
                                                        startMode,
                                                        autoCursorReset);
                                    } catch (Exception e) {
                                        throw new RuntimeException(e);
                                    }
                                    if (cursor.equals("")) {
                                        throw new RuntimeException("shard cursor error");
                                    }
                                    SlsSourceSplit split =
                                            new SlsSourceSplit(
                                                    project,
                                                    logStore,
                                                    consumer,
                                                    shard.getShardId(),
                                                    cursor,
                                                    fetachSize);
                                    pendingSplit.put(shard.getShardId(), split);
                                }
                            }
                        });
    }

    private String initShardCursor(
            String project,
            String logStore,

View on GitHub (pinned to cf67b549a7)