chartjs/Chart.js · error · Error

class does not have id: ${item}

Error message

class does not have id: ${item}

What it means

TypedRegistry.register(item) requires item.id to be a truthy string; without it the registry cannot scope defaults (scope + '.' + id) or store the component. The error stringifies the offending item so you can see what was passed. It is thrown when Chart.register(...) (or auto-registration) receives a class/object lacking a static `id` property.

Source

Thrown at src/core/core.typedRegistry.js:38

  /**
	 * @param {IChartComponent} item
	 * @returns {string} The scope where items defaults were registered to.
	 */
  register(item) {
    const proto = Object.getPrototypeOf(item);
    let parentScope;

    if (isIChartComponent(proto)) {
      // Make sure the parent is registered and note the scope where its defaults are.
      parentScope = this.register(proto);
    }

    const items = this.items;
    const id = item.id;
    const scope = this.scope + '.' + id;

    if (!id) {
      throw new Error('class does not have id: ' + item);
    }

    if (id in items) {
      // already registered
      return scope;
    }

    items[id] = item;
    registerDefaults(item, scope, parentScope);
    if (this.override) {
      defaults.override(item.id, item.overrides);
    }

    return scope;
  }

  /**
	 * @param {string} id

View on GitHub (pinned to cb02e1d207)

Solutions

  1. Add a static id to the component class: `class MyScale extends Scale { static id = 'myScale'; static defaults = {}; }`.
  2. Confirm every argument passed to Chart.register(...) is a class/object with a string `id`.
  3. Guard dynamic imports: only register when the imported value is defined and has an id.
  4. If registering an object form, ensure it has an `id` key (e.g. Chart.register({ id: 'myPlugin', ... })).

Example fix

// before
class MyPlugin {
  afterDraw(chart) { /* ... */ }
}
Chart.register(MyPlugin); // no static id -> throws

// after
class MyPlugin {
  static id = 'myPlugin';
  afterDraw(chart) { /* ... */ }
}
Chart.register(MyPlugin);
Defensive patterns

Strategy: validation

Validate before calling

// Validate that every item passed to Chart.register has an id.
import { Chart } from 'chart.js';

function registerSafely(...items) {
  for (const item of items) {
    if (!item || typeof item !== 'function' && typeof item !== 'object') {
      throw new Error('Chart.register received a non-component: ' + String(item));
    }
    if (!item.id || typeof item.id !== 'string') {
      throw new Error('Component missing static id: ' + (item.name || String(item)));
    }
  }
  Chart.register(...items);
}

Type guard

// Type guard ensuring a component class/object has an id.
function isRegistrableComponent(c) {
  return Boolean(c) && (typeof c === 'function' || typeof c === 'object') && typeof c.id === 'string' && c.id.length > 0;
}

Prevention

When it happens

Trigger: Calling Chart.register(MyClass) where MyClass has no static `id`; registering a plain object instead of a component class with an id; a custom plugin/scale/element/controller defined without an `id` static field; passing undefined/null into register() (e.g. a failed dynamic import).

Common situations: Authoring a custom Chart.js component and forgetting `static id = 'myThing'`; refactoring that renames/removes the id; bundler tree-shaking removing the static id assignment; copy-pasting a plugin snippet that omitted the id.

Related errors


AI-assisted analysis of chartjs/Chart.js@cb02e1d207 (2026-08-12). Data as JSON: /api/errors/9f922c327e1999c8. Report an issue: GitHub.