toeverything/AFFiNE · error · BlockSuiteError

ErrorCode.ValueNotExists

ErrorCode.ValueNotExists

Error message

Host is not ready to use, the `render` method should be called first

What it means

Thrown by the `BlockStdScope.host` getter in std-scope.ts. The scope holds a private `_host` that is only assigned when the `EditorHost` is mounted and `render()` has executed. Accessing `std.host` before that assignment triggers this `ValueNotExists` error — the host element does not yet exist.

Source

Thrown at blocksuite/framework/std/src/scope/std-scope.ts:98

  get command() {
    return this.get(CommandManager);
  }

  get event() {
    return this.get(UIEventDispatcher);
  }

  get get() {
    return this.provider.get.bind(this.provider);
  }

  get getOptional() {
    return this.provider.getOptional.bind(this.provider);
  }

  get host() {
    if (!this._host) {
      throw new BlockSuiteError(
        ErrorCode.ValueNotExists,
        'Host is not ready to use, the `render` method should be called first'
      );
    }

    return this._host;
  }

  get range() {
    return this.get(RangeManager);
  }

  get selection() {
    return this.get(StoreSelectionExtension);
  }

  get view() {
    return this.get(ViewStore);

View on GitHub (pinned to 26c515e050)

Solutions

  1. Move host-dependent code out of `created()` into the `rendered()` / `mounted()` lifecycle hook of the watcher or service.
  2. Guard with `if (this.std.host)` or use an optional accessor before invoking host APIs.
  3. Defer with `hostUpdated()` / `firstUpdated()` for Lit components.
  4. Use the `EditorLifeCycleExtension` hooks (`created`, `rendered`, `disposed`) in the correct order.

Example fix

// before: touching host in created() — runs before render
created() { this.std.host.addEventListener('keydown', this.onKey); }

// after: defer to the rendered() hook — host is assigned by then
rendered() { this.std.host.addEventListener('keydown', this.onKey); }
disposed() { this.std.host?.removeEventListener('keydown', this.onKey); }
Defensive patterns

Strategy: validation

Validate before calling

// guard host access in watchers/services
function getHostSafe(std: BlockStdScope): EditorHost | null {
  // `_host` is private; rely on a safe proxy if exposed, else check via try/catch
  try {
    return std.host;
  } catch {
    return null;
  }
}

const host = getHostSafe(this.std);
if (host) host.addEventListener('keydown', this.onKey);

Type guard

import type { BlockStdScope } from '@blocksuite/std';
import type { EditorHost } from '@blocksuite/std/view';

function stdHasHost(std: BlockStdScope): std is BlockStdScope & { host: EditorHost } {
  try {
    return !!std.host;
  } catch {
    return false;
  }
}

Try / catch

import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';

let host: EditorHost;
try {
  host = this.std.host;
} catch (e) {
  if (e instanceof BlockSuiteError && e.code === ErrorCode.ValueNotExists) {
    // not mounted yet; defer to the rendered() hook
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling `std.host`, `std.view`, or any API that routes through `host` (e.g. `blockComponent.host`, `renderChildren`, range/sync helpers) before `EditorHost` has rendered — typically inside a `BlockService.created()` hook, an `EditorLifeCycleExtension`, or a watcher's `created()` that runs during `BlockStdScope` construction.

Common situations: Service/watcher code that touches `std.host` synchronously in `created()` instead of waiting for the `mounted`/`rendered` lifecycle; using `std.host` in a constructor; a watcher that runs before the host has connected to the DOM.

Related errors


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