toeverything/AFFiNE · critical · BlockSuiteError

NoSurfaceModelError

NoSurfaceModelError

Error message

This doc is missing surface block in edgeless.

What it means

Thrown in the EdgelessRootBlockService constructor when getSurfaceBlock(this.doc) returns null — i.e. the doc has no surface block, which edgeless mode requires to hold vector/gfx primitive elements. Error code NoSurfaceModelError (a fatal-tier code > 10000). Construction of the service aborts, so the edgeless root block cannot initialise.

Source

Thrown at blocksuite/affine/blocks/root/src/edgeless/edgeless-root-service.ts:119

  }

  get viewport() {
    return this.std.get(GfxControllerIdentifier).viewport;
  }

  get zoom() {
    return this.viewport.zoom;
  }

  get crud() {
    return this.std.get(EdgelessCRUDIdentifier);
  }

  constructor(std: BlockStdScope, flavourProvider: { flavour: string }) {
    super(std, flavourProvider);
    const surface = getSurfaceBlock(this.doc);
    if (!surface) {
      throw new BlockSuiteError(
        ErrorCode.NoSurfaceModelError,
        'This doc is missing surface block in edgeless.'
      );
    }
    this._surface = surface;
  }

  private _initReadonlyListener() {
    const doc = this.doc;

    const slots = this.std.get(EdgelessLegacySlotIdentifier);

    let readonly = doc.readonly;
    this.disposables.add(
      effect(() => {
        if (readonly !== doc.readonly) {
          readonly = doc.readonly;
          slots.readonlyUpdated.next(readonly);

View on GitHub (pinned to 26c515e050)

Solutions

  1. Before entering edgeless mode, ensure the doc has a surface block: if !doc.root || !getSurfaceBlock(doc), add 'affine:surface' to the root before mounting the edgeless root block.
  2. If building a doc programmatically, always add a surface block alongside the page root when edgeless is supported.
  3. Run a repair migration over older docs to insert a missing surface block.

Example fix

// before
// doc has no surface block -> EdgelessRootBlockService constructor throws

// after
import { getSurfaceBlock } from '@blocksuite/affine-block-surface';
if (!getSurfaceBlock(doc)) {
  doc.addBlock('affine:surface', {}, doc.root!.id);
}
// now safe to initialise edgeless root service
Defensive patterns

Strategy: validation

Validate before calling

import { getSurfaceBlock } from '@blocksuite/affine-block-surface';
function ensureSurface(doc) {
  if (!getSurfaceBlock(doc)) {
    doc.captureSync();
    doc.addBlock('affine:surface', {}, doc.root.id);
  }
}

Type guard

import { getSurfaceBlock } from '@blocksuite/affine-block-surface';
function hasSurfaceBlock(doc): boolean {
  return !!getSurfaceBlock(doc);
}

Prevention

When it happens

Trigger: Mounting/initialising an edgeless root block on a doc that has no surface block. Happens when a doc was created as a page-only doc (no surface added), when the surface block was deleted, or when a custom doc-construction pipeline skipped adding 'affine:surface'.

Common situations: Opening a page-mode doc in edgeless mode without first ensuring a surface block; corrupted/incomplete docs; custom doc factories that omit the surface block; migrations that drop the surface block.

Related errors


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