toeverything/AFFiNE · error · BlockSuiteError

ValueNotExists

ValueNotExists

Error message

Failed to create portal root

What it means

For non-document tables the validator strictly rejects any data key that is not declared in table.schema — persisting undeclared fields would silently diverge from the persisted shape, and the adapters only store what the schema knows. Document tables (isDocumentTable) are exempt because they accept open shapes; regular tables fail with the offending key named.

Solutions

  1. Add the field to the table schema if it should be persisted
  2. Otherwise strip undeclared keys before the write: keep only Object.keys(table.schema)
  3. If open shapes are intended, use a document table instead of a regular table

Example fix

// before
table.insert({ data: { id: 'a1', name: 'x', tempFlag: true } }); // tempFlag not in schema

// after
// option A: persist it -> add to schema: tempFlag: { type: 'boolean' }
// option B: strip before write:
const data = Object.fromEntries(
  Object.entries(entity).filter(([k]) => k in table.schema)
);
table.insert({ data });
Defensive patterns

Strategy: validation

Validate before calling

function pickSchemaFields(data: Record<string, any>, schema: Record<string, unknown>) {
  return Object.fromEntries(Object.entries(data).filter(([key]) => key in schema));
}

table.insert({ data: pickSchemaFields(entity, table.schema) });

Type guard

null

Prevention

When it happens

Trigger: Inserting { id, name, tempFlag } when tempFlag was never added to the schema; renaming a field in code but not in the schema; computed/derived properties left on the object before insert; spreading a DTO (with transport-only fields) directly as entity data.

Common situations: Schema migration added the field to TypeScript types but not the table definition; reusing API DTOs as entities; newer client writing to an older schema.

Related errors


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

Appendix: source

Thrown at blocksuite/affine/components/src/portal/helper.ts:44

  identifyWrapper = true,
}: PortalOptions) {
  const portalRoot = document.createElement('div');
  if (identifyWrapper) {
    portalRoot.classList.add('blocksuite-portal');
  }
  if (shadowDom) {
    portalRoot.attachShadow({
      mode: 'open',
      ...(typeof shadowDom !== 'boolean' ? shadowDom : {}),
    });
  }
  signal.addEventListener('abort', () => {
    portalRoot.remove();
  });

  const root = shadowDom ? portalRoot.shadowRoot : portalRoot;
  if (!root) {
    throw new BlockSuiteError(
      BlockSuiteError.ErrorCode.ValueNotExists,
      'Failed to create portal root'
    );
  }

  let updateId = 0;
  const updatePortal: (id: number) => void = id => {
    if (id !== updateId) {
      console.warn(
        'Potentially infinite recursion! Please clean up the old event listeners before `updatePortal`'
      );
      return;
    }
    updateId++;
    const curId = updateId;
    const templateResult =
      template instanceof Function
        ? template({ updatePortal: () => updatePortal(curId) })

View on GitHub (pinned to b4c8548c09)