toeverything/AFFiNE · error · BlockSuiteError

ValueNotExists

ValueNotExists

Error message

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

What it means

The PrimaryKeyShouldExist data validator runs on write operations and requires data[table.keyField] to be neither undefined nor null. Without a key the row would be unaddressable in the adapter's key map, so the validator rejects the payload naming the table and the exact key field that is missing.

Solutions

  1. Set the primary key before insert — generate one explicitly (crypto.randomUUID()) if the schema has no generator
  2. Move key generation into the repository layer right before insert so no caller can forget it
  3. In dev builds, assert payload[table.keyField] != null before writing to fail with your own context

Example fix

// before
table.insert({ data: { name: 'x' } }); // keyField 'id' missing

// after
table.insert({ data: { id: crypto.randomUUID(), name: 'x' } });
Defensive patterns

Strategy: validation

Validate before calling

function withKey(table: { name: string; keyField: string }, data: Record<string, any>) {
  const val = data[table.keyField];
  if (val === undefined || val === null) {
    throw new Error(`${table.name}: missing primary key '${table.keyField}'`);
  }
  return data;
}
table.insert({ data: withKey(tableMeta, { id: crypto.randomUUID(), name: 'x' }) });

Type guard

null

Prevention

When it happens

Trigger: table.insert({ data: { name: 'x' } }) when the schema's keyField is 'id' but the payload omits it; the key is generated asynchronously and the insert was not awaited in order; the id field is explicitly set to null hoping for auto-generation (this ORM does not auto-generate in this path); spreading an object that never contained the key.

Common situations: Migrating from an ORM that auto-generates ids; forms submitting partial objects; fixture helper functions that forget to set the id field.

Related errors


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

Appendix: 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 b4c8548c09)