toeverything/AFFiNE · error · BlockSuiteError

ErrorCode.DefaultRuntimeError

ErrorCode.DefaultRuntimeError

Error message

Property ${propName} is required to ${instance.constructor.name}.

What it means

Thrown by `validatePropTypes` inside the `@requiredProperties` decorator (required.ts). When a LitElement decorated with `@requiredProperties({...})` calls `connectedCallback`, each declared property is checked; if any is `undefined`, this error fires naming the missing property and component class. It is a compile-time-like runtime contract: the consumer forgot to bind a required property.

Source

Thrown at blocksuite/framework/std/src/view/decorators/required.ts:31

  instanceOf: (expectedClass: Constructor) => (value: unknown) =>
    value instanceof expectedClass,
  arrayOf: (validator: ValidatorFunction) => (value: unknown) =>
    Array.isArray(value) && value.every(validator),
  recordOf: (validator: ValidatorFunction) => (value: unknown) => {
    if (typeof value !== 'object' || value === null) return false;
    return Object.values(value).every(validator);
  },
  of: (validator: ValidatorFunction) => (value: unknown) => validator(value),
};

function validatePropTypes<T extends InstanceType<Constructor>>(
  instance: T,
  propTypes: Record<string, ValidatorFunction>
) {
  for (const [propName, validator] of Object.entries(propTypes)) {
    const key = propName as keyof T;
    if (instance[key] === undefined) {
      throw new BlockSuiteError(
        ErrorCode.DefaultRuntimeError,
        `Property ${propName} is required to ${instance.constructor.name}.`
      );
    }
    if (validator && !validator(instance[key])) {
      throw new BlockSuiteError(
        ErrorCode.DefaultRuntimeError,
        `Property ${propName} is invalid to ${instance.constructor.name}.`
      );
    }
  }
}

export function requiredProperties(
  propTypes: Record<string, ValidatorFunction>
) {
  return function (constructor: Constructor<LitElement>) {
    const connectedCallback = constructor.prototype.connectedCallback;

View on GitHub (pinned to 26c515e050)

Solutions

  1. Pass the named property before the element connects: `<my-block .model=${model} .store=${store}></my-block>`.
  2. If the property is genuinely optional, remove it from the `@requiredProperties` map or change it to a validator that permits `undefined`.
  3. Ensure parent templates do not render the component until all required data is non-undefined.

Example fix

// before: required prop not bound
@requiredProperties({ model: PropTypes.object })
class MyBlock extends LitElement {}
html`<my-block></my-block>`

// after: bind the prop before connect
html`<my-block .model=${model}></my-block>`
Defensive patterns

Strategy: validation

Validate before calling

// before rendering a @requiredProperties-decorated component, ensure props are set
function hasRequiredProps(
  props: Record<string, unknown>,
  required: string[]
): boolean {
  return required.every(k => props[k] !== undefined);
}

const required = ['model', 'store'];
if (hasRequiredProps({ model, store }, required)) {
  render(html`<my-block .model=${model} .store=${store}></my-block>`, container);
}

Type guard

function hasAllRequired<T extends object>(obj: T, keys: Array<keyof T>): obj is T {
  return keys.every(k => obj[k] !== undefined);
}

Try / catch

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

try {
  container.appendChild(myBlock); // triggers connectedCallback -> validatePropTypes
} catch (e) {
  if (e instanceof BlockSuiteError && e.code === ErrorCode.DefaultRuntimeError) {
    console.error('Missing required property:', e.message);
  }
}

Prevention

When it happens

Trigger: A `@requiredProperties`-decorated block/component is mounted (connected) without one of the declared properties being set — e.g. `<my-block>` rendered without `.model` or `.store`.

Common situations: Forgetting to pass a required property/attribute when composing a block; conditional rendering that yields a block before its props are ready; refactoring a component and adding a new required prop without updating call sites.

Related errors


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