alibaba/canal · error · CanalException
{} has startup , don't repeat start
Error message
{} has startup , don't repeat start What it means
Thrown by AbstractCanalLifeCycle.start() when the component's `running` flag is already true. This is a double-start guard common to all Canal lifecycle components (CanalInstance, CanalServer, MetaManager, etc.). The volatile running flag ensures visibility across threads, and the non-atomic check-then-set means concurrent start() calls from different threads can both observe running==false, but the second setter is a no-op that does not throw — the throw only fires when running was already true before the call.
Source
Thrown at common/src/main/java/com/alibaba/otter/canal/common/AbstractCanalLifeCycle.java:19
package com.alibaba.otter.canal.common;
/**
* 基本实现
*
* @author jianghang 2012-7-12 上午10:11:07
* @version 1.0.0
*/
public abstract class AbstractCanalLifeCycle implements CanalLifeCycle {
protected volatile boolean running = false; // 是否处于运行中
public boolean isStart() {
return running;
}
public void start() {
if (running) {
throw new CanalException(this.getClass().getName() + " has startup , don't repeat start");
}
running = true;
}
public void stop() {
if (!running) {
throw new CanalException(this.getClass().getName() + " isn't start , please check");
}
running = false;
}
}
View on GitHub (pinned to 87be50e876)
Solutions
- Check `component.isStart()` before calling `component.start()` to avoid double-start.
- Ensure stop() is always called before re-starting a component in restart procedures.
- Use a single lifecycle manager to control start/stop ordering and prevent concurrent lifecycle calls.
- Add proper shutdown hooks so components are stopped before the JVM exits, preventing stale running state.
Example fix
// before
if (!canalInstance.isStart()) {
canalInstance.start();
}
// Note: this has a TOCTOU race in concurrent contexts.
// For single-threaded lifecycle management:
canalInstance.start(); // safe if guaranteed not already started
// idiomatic guard
if (canalInstance.isStart()) {
canalInstance.stop();
}
canalInstance.start(); Defensive patterns
Strategy: validation
Validate before calling
// Guard double-start
if (!component.isStart()) {
component.start();
} else {
logger.info("{} is already started, skipping", component.getClass().getSimpleName());
} Type guard
null
Try / catch
try {
component.start();
} catch (CanalException e) {
if (e.getMessage() != null && e.getMessage().contains("don't repeat start")) {
logger.info("Component already started: {}", component.getClass().getName());
} else {
throw e;
}
} Prevention
- Always check isStart() before calling start().
- Centralize lifecycle management in a single coordinator to prevent concurrent start calls.
- Ensure stop() is called in shutdown hooks before restart procedures.
When it happens
Trigger: Calling start() on a CanalLifeCycle component that is already running — e.g. calling canalServer.start() twice, or calling start() on a CanalInstance that was not stopped after a previous start.
Common situations: Lifecycle management code calls start() without first checking isStart(); a restart procedure fails to stop() before start(); multiple threads or initialization blocks both call start(); embedded canal usage where the application lifecycle and canal lifecycle are not synchronized.
Related errors
- {} isn't start , please check
- Invalid destination path
- Failed to read file
- zk client has already been started
- Disconnect pulsar consumer error
AI-assisted analysis of alibaba/canal@87be50e876 (2026-08-14).
Data as JSON: /api/errors/bbc3c10b3fd87782.
Report an issue: GitHub.