alibaba/spring-ai-alibaba · error · IllegalStateException
ConfigAgentWatcher is already started
Error message
ConfigAgentWatcher is already started
What it means
ConfigAgentWatcher.start() throws IllegalStateException when invoked on a watcher instance whose `started` flag is already true. A watcher schedules a repeating file-check task and must only be started once per instance. Starting it again would leak duplicate scheduled tasks that each fire change callbacks.
Source
Thrown at spring-ai-alibaba-studio/src/main/java/com/alibaba/cloud/ai/agent/studio/loader/ConfigAgentWatcher.java:56
* <p>The watcher polls for changes at regular intervals rather than using native filesystem events
* for better cross-platform compatibility.
*/
class ConfigAgentWatcher {
private static final Logger logger = LoggerFactory.getLogger(ConfigAgentWatcher.class);
private final Map<Path, ChangeCallback> watchedFolders = new ConcurrentHashMap<>();
private final Map<Path, Map<Path, Long>> watchedYamlFiles = new ConcurrentHashMap<>();
private final ScheduledExecutorService fileWatcher = Executors.newSingleThreadScheduledExecutor();
private volatile boolean started = false;
/**
* Starts watching for file changes.
*
* @throws IllegalStateException if the watcher is already started
*/
synchronized void start() {
if (started) {
throw new IllegalStateException("ConfigAgentWatcher is already started");
}
logger.info("Starting ConfigAgentWatcher");
fileWatcher.scheduleAtFixedRate(this::checkForChanges, 2, 2, TimeUnit.SECONDS);
started = true;
Runtime.getRuntime().addShutdownHook(new Thread(this::stop));
logger.info(
"ConfigAgentWatcher started successfully. Watching {} folders.", watchedFolders.size());
}
/** Stops the file watcher. */
synchronized void stop() {
if (!started) {
return;
}
logger.info("Stopping ConfigAgentWatcher...");View on GitHub (pinned to f82da0b50f)
Solutions
- Guard the call: only invoke start() if the watcher has not been started (track a boolean or check the watcher's state)
- Create a fresh ConfigAgentWatcher instance instead of restarting the old one
- Consolidate bootstrap logic so start() is called from exactly one lifecycle hook
- Catch IllegalStateException around start() if double-start is benign in your flow
Example fix
// before
watcher.start(); // called from @PostConstruct and again from onApplicationEvent
// after
if (!watcherStarted.getAndSet(true)) {
watcher.start();
} Defensive patterns
Strategy: try-catch
Validate before calling
if (watcherStarted) { throw new IllegalStateException("watcher already started"); } Try / catch
try {
watcher.start();
} catch (IllegalStateException alreadyStarted) {
logger.debug("Watcher already running; ignoring duplicate start");
} Prevention
- Start the watcher from exactly one lifecycle hook (e.g. only @PostConstruct, not also ApplicationReadyEvent)
- Track start state in your own AtomicBoolean before calling start()
- If restart is needed, build a new ConfigAgentWatcher instead of reusing the old instance
When it happens
Trigger: Calling start() twice on the same ConfigAgentWatcher instance — e.g. calling start() in both a @PostConstruct hook and application-ready listener, restarting the app lifecycle without creating a new watcher, or a retry path re-invoking start().
Common situations: Spring bean lifecycle callbacks firing start() more than once; manual re-init code reusing an old watcher object; copy-pasted bootstrap code calling start() in multiple configuration classes.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Schedule already started
- Cannot create update map after mergeAll() has been called
- mergeAll() can only be called once
- Shell session not initialized. Call initialize() before exec
- Default Scheduled Agent Manager is shut down
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/82f1aeb2fd39d3b9.
Report an issue: GitHub.