alibaba/canal · warning · CanalClientException

Failed to fetch the data after: ${timeout}

Error message

Failed to fetch the data after: ${timeout}

What it means

Thrown by CanalRabbitMQConsumer.getMessage when messageBlockingQueue.poll(timeout, unit) is interrupted (InterruptedException) while waiting for a batch. It is not a broker error — it means the consumer thread was signaled to stop (interrupt()) while blocked waiting for messages to arrive.

Source

Thrown at connector/rabbitmq-connector/src/main/java/com/alibaba/otter/canal/connector/rabbitmq/consumer/CanalRabbitMQConsumer.java:176

        boolean isSuccess = batchMessage.isSuccess();
        return isCompleted && isSuccess;
    }

    @Override
    public List<CommonMessage> getMessage(Long timeout, TimeUnit unit) {
        try {
            if (this.lastGetBatchMessage != null) {
                throw new CanalClientException("mq get/ack not support concurrent & async ack");
            }

            ConsumerBatchMessage<CommonMessage> batchMessage = messageBlockingQueue.poll(timeout, unit);
            if (batchMessage != null) {
                this.lastGetBatchMessage = batchMessage;
                return batchMessage.getData();
            }
        } catch (InterruptedException ex) {
            logger.warn("Get message timeout", ex);
            throw new CanalClientException("Failed to fetch the data after: " + timeout);
        }
        return null;
    }

    @Override
    public void rollback() {
        try {
            if (this.lastGetBatchMessage != null) {
                this.lastGetBatchMessage.fail();
            }
        } finally {
            this.lastGetBatchMessage = null;
        }
    }

    @Override
    public void ack() {
        try {

View on GitHub (pinned to 87be50e876)

Solutions

  1. If during shutdown, treat it as expected: log and exit cleanly, restoring the interrupt status with Thread.currentThread().interrupt().
  2. If unexpected, find the caller invoking interrupt() on the consumer thread and avoid interrupting it mid-poll.
  3. Increase the poll timeout if you want fewer wake-ups, but the interrupt itself is an external signal, not a timeout of the broker.

Example fix

// before
} catch (InterruptedException ex) {
    logger.warn("Get message timeout", ex);
    throw new CanalClientException("Failed to fetch the data after: " + timeout);
}

// after — distinguish interruption from a real timeout
} catch (InterruptedException ex) {
    logger.warn("Get message interrupted", ex);
    Thread.currentThread().interrupt(); // restore flag
    throw new CanalClientException("Get message interrupted after: " + timeout);
}
Defensive patterns

Strategy: try-catch

Try / catch

} catch (InterruptedException ex) {
    logger.warn("Get message interrupted", ex);
    Thread.currentThread().interrupt();
    // during shutdown: return empty; otherwise rethrow
    if (isShuttingDown()) return Collections.emptyList();
    throw new CanalClientException("Get message interrupted after: " + timeout);
}

Prevention

When it happens

Trigger: poll(timeout, unit) at line 171 throws InterruptedException because Thread.interrupt() was invoked on the consuming thread — typical during application shutdown or executor shutdownNow().

Common situations: Container/scheduler shutting down the consumer thread; explicit thread.interrupt() during stop; Spring/executor shutdownNow() interrupting blocked tasks. The message is benign if it occurs during a controlled shutdown.

Understand the failure class

Related errors


AI-assisted analysis of alibaba/canal@87be50e876 (2026-08-14). Data as JSON: /api/errors/21c29edc21e1e12c. Report an issue: GitHub.