{"record":{"id":"ee1b8b54693f1b6d","repo":"alibaba/druid","slug":"no-observer-such-as-poolupdater-specified","errorCode":null,"errorMessage":"No Observer(such as PoolUpdater) specified.","messagePattern":"No Observer\\(such as PoolUpdater\\) specified\\.","errorType":"exception","errorClass":"DruidRuntimeException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/com/alibaba/druid/pool/ha/node/NodeListener.java","lineNumber":55,"sourceCode":"\n    /**\n     * The method implements the detail update logic.\n     */\n    public abstract List<NodeEvent> refresh();\n\n    /**\n     * Do some cleanup.\n     */\n    public abstract void destroy();\n\n    /**\n     * Add the given PoolUpdater as the Observer.\n     *\n     * @see #setObserver(Observer)\n     */\n    public void init() {\n        if (observer == null) {\n            throw new DruidRuntimeException(\"No Observer(such as PoolUpdater) specified.\");\n        }\n        this.addObserver(observer);\n    }\n\n    /**\n     * Fire the refresh() method and notify the Observer.\n     *\n     * @see #refresh()\n     * @see #update(List)\n     */\n    public void update() {\n        update(refresh());\n    }\n\n    /**\n     * Notify the Observer.\n     */\n    public void update(List<NodeEvent> events) {","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/alibaba/druid/blob/fa8dc9912637a2f729eef9f55356621fec18d40e/core/src/main/java/com/alibaba/druid/pool/ha/node/NodeListener.java#L37-L73","documentation":"NodeListener.init() requires an Observer (typically a PoolUpdater) to be registered before it can begin watching for node changes, because NodeListener extends Observable and forwards detected node add/remove events to that observer. Calling init() with observer==null means the listener would have nowhere to deliver events, so Druid refuses to start.","triggerScenarios":"Constructing a NodeListener (e.g. ZookeeperNodeListener, FileNodeListener) and calling init() (directly or via the HA DataSource bootstrap that calls selector.init() -> NodeListener.init()) without first calling setObserver(...).","commonSituations":"Custom integration wiring HighAvailableDataSource manually and forgetting the PoolUpdater; upgrading Druid versions where the wiring API changed; copying example code that omitted the observer step.","solutions":["Call nodeListener.setObserver(new PoolUpdater(dataSource)) before nodeListener.init().","Prefer the HighAvailableDataSource high-level API, which wires the observer automatically, over manual NodeListener construction.","Verify the observer field is non-null in a startup sanity check so misconfiguration fails early with your own message."],"exampleFix":"// before\nNodeListener listener = new ZookeeperNodeListener();\nlistener.init(); // throws 'No Observer specified.'\n\n// after\nNodeListener listener = new ZookeeperNodeListener();\nlistener.setObserver(new PoolUpdater(haDataSource));\nlistener.init();","handlingStrategy":"validation","validationCode":"if (nodeListener.getObserver() == null) {\n    throw new IllegalStateException(\"set a PoolUpdater via nodeListener.setObserver(...) before init()\");\n}\nnodeListener.init();","typeGuard":"public static boolean readyToInit(NodeListener l) {\n    return l.getObserver() != null;\n}","tryCatchPattern":null,"preventionTips":["Always call setObserver(new PoolUpdater(dataSource)) before init().","Prefer the HighAvailableDataSource high-level API, which wires the observer for you.","Add a startup sanity check that observer/path/urlTemplate are all set."],"tags":["ha-datasource","node-listener","configuration","observer-pattern"],"backgroundTag":null,"analyzedSha":"fa8dc9912637a2f729eef9f55356621fec18d40e","analyzedAt":"2026-08-14T04:55:06.789Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}