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

  1. Check `component.isStart()` before calling `component.start()` to avoid double-start.
  2. Ensure stop() is always called before re-starting a component in restart procedures.
  3. Use a single lifecycle manager to control start/stop ordering and prevent concurrent lifecycle calls.
  4. 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

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


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