toeverything/AFFiNE · error · BlockSuiteError

ErrorCode.MissingViewModelError

ErrorCode.MissingViewModelError

Error message

Cannot find block model for id ${this.blockId}

What it means

BlockComponent.model getter resolves the component's blockId through store.getModelById(); if the doc no longer contains a model with that id it throws MissingViewModelError instead of returning undefined. This happens when a view component outlives its model — the block was deleted from the yjs doc but the custom element is still mounted or being read.

Solutions

  1. Check existence before use: const model = doc.getModelById(component.blockId); if (!model) skip teardown logic.
  2. Do removals through the standard APIs (doc.deleteBlock) so views unmount with the model; let the view registry drive element lifetime.
  3. Never cache BlockComponent instances across mutations — re-query via std.view.getBlock(id).
  4. In custom components, avoid touching this.model after disconnectedCallback.

Example fix

// before
const comp = std.view.getBlock(id);
const flavour = comp.model.flavour; // throws if model deleted

// after
const comp = std.view.getBlock(id);
const model = comp ? doc.getModelById(comp.blockId) : null;
if (!model) return;
const flavour = model.flavour;
Defensive patterns

Strategy: type-guard

Validate before calling

const model = doc.getModelById(component.blockId);
if (model) {
  // safe to read component.model / render
}

Type guard

function blockModelExists(doc: Store, blockId: string): boolean {
  return doc.getModelById(blockId) != null;
}

Prevention

When it happens

Trigger: Reading this.model (directly or via parentComponent/childComponent/render) on a BlockComponent whose blockId has no model in the store: block deleted while its element was still connected, a stale element retained after a view re-render, or a component created with a wrong/unset blockId.

Common situations: Deleting blocks programmatically while their components are mid-lifecycle; undo/redo replacing a model id; custom code holding references to block components past deletion; snapshot import that doesn't map ids consistently.

Related errors


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

Appendix: source

Thrown at blocksuite/framework/std/src/view/element/block-component.ts:114

    const expectedVersion = schema.version;
    const actualVersion = this.model.version;
    if (expectedVersion !== actualVersion) {
      console.warn(
        `Version mismatch for block ${this.model.id}, expected ${expectedVersion}, actual ${actualVersion}`
      );
      return true;
    }

    return false;
  }

  get model() {
    if (this._model) {
      return this._model;
    }
    const model = this.store.getModelById<Model>(this.blockId);
    if (!model) {
      throw new BlockSuiteError(
        ErrorCode.MissingViewModelError,
        `Cannot find block model for id ${this.blockId}`
      );
    }
    this._model = model;
    return model;
  }

  get parentComponent(): BlockComponent | null {
    const parent = this.model.parent;
    if (!parent) return null;
    return this.std.view.getBlock(parent.id);
  }

  get renderChildren() {
    return this.host.renderChildren.bind(this);
  }

View on GitHub (pinned to b4c8548c09)