apache/seatunnel · critical · PulsarConnectorException

CommonErrorCodeDeprecated.READER_OPERATION_FAILED

CommonErrorCodeDeprecated.READER_OPERATION_FAILED

Error message

Failed to start the split reader thread.

What it means

PulsarSourceReader.addSplits creates and starts a PulsarSplitReaderThread for each new split. Opening the underlying Pulsar consumer can throw PulsarClientException, which is wrapped as READER_OPERATION_FAILED with this message. Data reading cannot start for the affected split because the Pulsar consumer could not be created/started.

Source

Thrown at seatunnel-connectors-v2/connector-pulsar/src/main/java/org/apache/seatunnel/connectors/seatunnel/pulsar/source/reader/PulsarSourceReader.java:199

    @Override
    public void addSplits(List<PulsarPartitionSplit> splits) {
        for (PulsarPartitionSplit split : splits) {
            splitStates.put(split.splitId(), split);
            TablePath tablePath = resolveTablePath(split);
            if (tablePath != null) {
                splitIdToTablePath.put(split.splitId(), tablePath);
            }
            PulsarSplitReaderThread splitReaderThread = createPulsarSplitReaderThread(split);
            try {
                splitReaderThread.setName(
                        "Pulsar Source Data Consumer " + split.getPartition().getPartition());
                splitReaderThread.open();
                splitReaders.put(split.splitId(), splitReaderThread);
                splitReaderThread.start();
                LOG.info("PulsarSplitReaderThread = {} start", splitReaderThread.getName());
            } catch (PulsarClientException e) {
                throw new PulsarConnectorException(
                        CommonErrorCodeDeprecated.READER_OPERATION_FAILED,
                        "Failed to start the split reader thread.",
                        e);
            }
        }
    }

    protected PulsarSplitReaderThread createPulsarSplitReaderThread(PulsarPartitionSplit split) {
        PulsarConsumerMetadata metadata = resolveConsumerMetadata(resolveTablePath(split));
        return new PulsarSplitReaderThread(
                this,
                split,
                pulsarClient,
                metadata.getConsumerConfig(),
                pollTimeout,
                pollInterval,
                metadata.getStartCursor(),
                handover);

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Verify service.url (pulsar://host:6650) is reachable and the broker is up; check the wrapped PulsarClientException cause.
  2. Ensure the subscription.name exists or that start.mode/SUBSCRIPTION setup creates it; resolve exclusive-subscription conflicts with other consumers.
  3. Check Pulsar authentication/authorization (token, TLS) configuration on both client and broker side.
  4. Confirm the topic (and partitions) still exist; recreate deleted topics or update the config.

Example fix

// before
service.url = "pulsar://localhost:8080"
// after
service.url = "pulsar://localhost:6650"
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight connectivity check
try (PulsarClient c = PulsarClient.builder().serviceUrl(serviceUrl).build()) { /* ok */ }
// plus: ensure subscription exists
admin.topics().getSubscriptions(topic).contains(subscriptionName);

Try / catch

try {
    reader.addSplits(splits);
} catch (PulsarConnectorException e) {
    if (e.getErrorCode() == CommonErrorCodeDeprecated.READER_OPERATION_FAILED
            && e.getCause() instanceof PulsarClientException) {
        // retry with backoff; check broker availability and exclusive-subscription conflicts
    }
    throw e;
}

Prevention

When it happens

Trigger: Assigning a split whose consumer open() fails with PulsarClientException — broker unreachable at service.url, subscription does not exist in Exclusive/Failover mode conflict, authentication failure, or topic deleted.

Common situations: Wrong service.url or port (6650 vs admin 8080); subscription already connected from another client (exclusive consumer conflict); missing subscription when start.mode = SUBSCRIPTION; TLS/auth misconfiguration.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


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