liriliri/eruda · warning

Tool ${name} already exists

Error message

Tool ${name} already exists

What it means

devtools.add(tool) registers a tool keyed by its `name` property in the internal `this._tools` map and creates a tab/panel for it. If a tool with the same name is already registered, the library refuses to add a duplicate and logs this warning instead, leaving the existing tool untouched. It's a guard against silent overwriting of an already-initialized tool panel.

Source

Thrown at src/DevTools/DevTools.js:111

  }
  toggle() {
    return this._isShow ? this.hide() : this.show()
  }
  add(tool) {
    const tab = this._tab

    if (!(tool instanceof Tool)) {
      const { init, show, hide, destroy } = new Tool()
      defaults(tool, { init, show, hide, destroy })
    }

    const name = tool.name
    if (!name) {
      return logger.error('You must specify a name for a tool')
    }

    if (this._tools[name]) {
      return logger.warn(`Tool ${name} already exists`)
    }

    const id = name.replace(/\s+/g, '-')
    this._$tools.prepend(`<div id="${c(id)}" class="${c(id + ' tool')}"></div>`)
    tool.init(this._$tools.find(`.${c(id)}.${c('tool')}`), this)
    tool.active = false
    this._tools[name] = tool

    if (name === 'settings') {
      tab.append({
        id: name,
        title: name,
      })
    } else {
      tab.insert(tab.length - 1, {
        id: name,
        title: name,
      })

View on GitHub (pinned to 0c55928fec)

Solutions

  1. Check devtools.get(name) before calling add() and skip if the tool already exists.
  2. Call devtools.remove(name) before re-adding the tool, or use devtools.removeAll() during teardown.
  3. Rename your custom tool so its `name` is unique and doesn't collide with built-in tools.
  4. Guard the add() call so it runs only once (e.g. a module-level flag or init-once pattern) to survive HMR.
  5. If the duplicate add is intentional and harmless, the warning can be safely ignored — the original tool stays active.

Example fix

// before
eruda.add(myTool)

// after
if (!eruda.get('myTool')) {
  eruda.add(myTool)
}
Defensive patterns

Strategy: validation

Validate before calling

if (!devtools.get(tool.name)) {
  devtools.add(tool)
}

Type guard

function canAdd(devtools, tool) {
  return tool && typeof tool.name === 'string' && tool.name.length > 0 && !devtools.get(tool.name);
}

Prevention

When it happens

Trigger: Calling devtools.add(tool) (or eruda.add(tool)) with a tool whose `name` matches a tool already added — e.g. calling add() twice with the same tool instance, adding two custom tools that share a name, re-running an init script that adds a built-in tool like 'settings' or 'elements' again, or hot module reloading re-executing the add() call without removing the old tool.

Common situations: HMR/dev-server reload re-running setup code; initializing eruda in multiple scripts or bundles that each call add(); writing a custom plugin whose name collides with a built-in tool name; accidentally passing the same tool object in a loop or an event handler that fires more than once.

Related errors


AI-assisted analysis of liriliri/eruda@0c55928fec (2026-09-01). Data as JSON: /api/errors/7b53723c1af2cf44. Report an issue: GitHub.