phaserjs/phaser · error · Error

node

Error message

node 

What it means

Thrown by RenderNodeManager.addNode when a node is registered under a name that already exists in this._nodes. Names are unique keys into the render-graph registry because getNode looks nodes up by name and the system assumes one instance per name.

Source

Thrown at src/renderer/webgl/renderNodes/RenderNodeManager.js:310

         * @default null
         */
        this.currentDebugNode = null;
    },

    /**
     * Add a node to the manager.
     *
     * @method Phaser.Renderer.WebGL.RenderNodes.RenderNodeManager#addNode
     * @since 4.0.0
     * @param {string} name - The name of the node.
     * @param {Phaser.Renderer.WebGL.RenderNodes.RenderNode} node - The node to add.
     * @throws {Error} Will throw an error if the node already exists.
     */
    addNode: function (name, node)
    {
        if (this._nodes[name])
        {
            throw new Error('node ' + name + ' already exists.');
        }
        this._nodes[name] = node;

        // If a node is somehow added during a debug render pass,
        // ensure that it is also set to debug.
        if (this.debug)
        {
            node.setDebug(true);
        }
    },

    /**
     * Add a constructor for a node to the manager.
     * This will allow the node to be constructed when `getNode` is called.
     *
     * @method Phaser.Renderer.WebGL.RenderNodes.RenderNodeManager#addNodeConstructor
     * @since 4.0.0
     * @param {string} name - The name of the node.

View on GitHub (pinned to 41be1e462b)

Solutions

  1. Namespace your node names (e.g. 'MyPlugin.BatchHandler') to avoid collisions with built-ins and other plugins.
  2. Before adding, check manager._nodes[name] or guard with a removeNode call if re-registering is expected.
  3. On teardown/hot-reload, remove previously added nodes before re-adding them.
  4. Use addNodeConstructor + getNode (lazy construction) instead of eagerly adding duplicate instances.

Example fix

// before
manager.addNode('Batch', nodeA);
manager.addNode('Batch', nodeB); // throws

// after
if (!manager._nodes['Batch']) {
  manager.addNode('Batch', nodeA);
} else {
  manager.removeNode('Batch');
  manager.addNode('Batch', nodeB);
}
Defensive patterns

Strategy: validation

Validate before calling

if (manager._nodes[name]) { /* skip or remove+re-add */ } else { manager.addNode(name, node); }

Type guard

function isNodeRegistered(manager, name) { return Boolean(manager._nodes && manager._nodes[name]); }

Try / catch

try { manager.addNode(name, node); } catch (e) { if (/already exists/.test(e.message)) { manager.removeNode(name); manager.addNode(name, node); } else throw e; }

Prevention

When it happens

Trigger: Calling manager.addNode(name, node) twice with the same name string; adding a node whose name collides with a built-in node (e.g. 'BatchHandlerQuad'); a plugin or scene adding a node that another plugin already registered.

Common situations: Two plugins registering custom render nodes with the same name; hot-reloading a scene/plugin that re-adds its nodes without tearing down the old ones; reusing a generic name like 'batch' across modules.

Related errors


AI-assisted analysis of phaserjs/phaser@41be1e462b (2026-08-13). Data as JSON: /api/errors/45ccb99bab085edf. Report an issue: GitHub.