alibaba/canal · error · CanalException
{} isn't start , please check
Error message
{} isn't start , please check What it means
Thrown by AbstractCanalLifeCycle.stop() when the component's `running` flag is false. This is the counterpart to the double-start guard — it prevents stopping a component that was never started or was already stopped. The `running` flag is volatile for cross-thread visibility.
Source
Thrown at common/src/main/java/com/alibaba/otter/canal/common/AbstractCanalLifeCycle.java:27
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.stop()`.
- In finally/cleanup blocks, guard stop() with an isStart() check to handle cases where start() never succeeded.
- Track lifecycle state explicitly in application code to avoid redundant stop() calls.
- Swallow CanalException in shutdown hooks if a clean stop is best-effort.
Example fix
// before — unconditional stop in finally
try {
canalServer.start();
} finally {
canalServer.stop(); // throws if start() failed
}
// after — guarded stop
try {
canalServer.start();
} finally {
if (canalServer.isStart()) {
canalServer.stop();
}
} Defensive patterns
Strategy: validation
Validate before calling
// Guard double-stop
if (component.isStart()) {
component.stop();
} else {
logger.info("{} is not running, skip stop", component.getClass().getSimpleName());
} Type guard
null
Try / catch
// In finally/cleanup blocks, swallow the 'isn't start' exception gracefully
try {
if (component.isStart()) {
component.stop();
}
} catch (CanalException e) {
if (e.getMessage() != null && e.getMessage().contains("isn't start")) {
logger.debug("Component already stopped: {}", component.getClass().getName());
} else {
throw e;
}
} Prevention
- Always check isStart() before calling stop().
- In finally blocks, guard stop() calls since start() may not have succeeded.
- Use idempotent shutdown procedures that tolerate being called when already stopped.
When it happens
Trigger: Calling stop() on a CanalLifeCycle component that is not currently running — e.g. calling canalServer.stop() after it was already stopped, or calling stop() on a component whose start() failed or was never invoked.
Common situations: Shutdown hook fires after a failed start (component never reached running state); double-stop in cleanup code; stop() called on a component that threw during start(); application error handling calls stop() unconditionally in a finally block.
Related errors
- {} has startup , don't repeat start
- 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/2856fb600f0bb07b.
Report an issue: GitHub.