toeverything/AFFiNE · error · BlockSuiteError

ValueNotExists

ValueNotExists

Error message

The overlay constructor '${this.name}' should have a static 'overlayName' property.

What it means

Thrown by Overlay.setup (static DI hook) when the Overlay subclass has not overridden the static 'overlayName' property (it defaults to ''). The overlayName is used to build OverlayIdentifier(this.overlayName) for DI resolution; an empty name makes the overlay unidentifiable. Error code ValueNotExists. This is a registration-time developer error, raised during editor extension setup.

Source

Thrown at blocksuite/affine/blocks/surface/src/renderer/overlay.ts:27

import type { RoughCanvas } from '../utils/rough/canvas.js';
import type { CanvasRenderer } from './canvas-renderer.js';

/**
 * An overlay is a layer covered on top of elements,
 * can be used for rendering non-CRDT state indicators.
 */
export abstract class Overlay extends Extension {
  static overlayName: string = '';

  protected _renderer: CanvasRenderer | null = null;

  constructor(protected gfx: GfxController) {
    super();
  }

  static override setup(di: Container): void {
    if (!this.overlayName) {
      throw new BlockSuiteError(
        ErrorCode.ValueNotExists,
        `The overlay constructor '${this.name}' should have a static 'overlayName' property.`
      );
    }

    di.addImpl(OverlayIdentifier(this.overlayName), this, [
      GfxControllerIdentifier,
    ]);
  }

  clear() {
    this.refresh();
  }

  dispose() {}

  refresh() {
    if (this._renderer) {

View on GitHub (pinned to 26c515e050)

Solutions

  1. Declare a unique static overlayName on every Overlay subclass: `static override overlayName = 'my-overlay';`.
  2. Add a compile-time/test check that imports each Overlay subclass and asserts Subclass.overlayName is a non-empty string.
  3. Names are DI keys — keep them stable across versions and avoid collisions with built-in overlays.

Example fix

// before
class MyOverlay extends Overlay {
  // no overlayName -> setup throws ValueNotExists
  render(ctx, rc) { ... }
}

// after
class MyOverlay extends Overlay {
  static override overlayName = 'my-overlay';
  render(ctx, rc) { ... }
}
Defensive patterns

Strategy: validation

Validate before calling

import { Overlay } from '@blocksuite/affine-block-surface';
// assert at module load / in a test:
if (typeof MyOverlay.overlayName !== 'string' || !MyOverlay.overlayName) {
  throw new Error('MyOverlay must define static overlayName');
}

Type guard

function hasOverlayName(Ctor) {
  return typeof Ctor.overlayName === 'string' && Ctor.overlayName.length > 0;
}

Prevention

When it happens

Trigger: Authoring a custom Overlay subclass (a canvas layer drawn on top of elements, e.g. selection handles, alignment guides) and registering it without setting `static overlayName = '...'`. The framework calls setup(di) at init and throws.

Common situations: New overlay written by following an example that omitted overlayName; refactor that moved the field; subclassing Overlay indirectly and forgetting the static field; collision-free naming not enforced so a developer skips it.

Related errors


AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12). Data as JSON: /api/errors/6c8efc28bf236a5b. Report an issue: GitHub.