toeverything/AFFiNE · error · Error

props is only supported in flat data model

Error message

props is only supported in flat data model

What it means

BlockModel.props returns the reactive proxy stored in _props, but only FlatSyncController ever assigns _props — it is used when a block's schema declares isFlatData: true (block.ts:54). In the default tree data model, SyncController copies props directly onto the model instance and leaves _props undefined, so this getter throws to signal that the proxy API does not exist for this block.

Source

Thrown at blocksuite/framework/store/src/model/block/block-model.ts:83

  stash!: (prop: keyof Props & string) => void;

  get text(): Text | undefined {
    return (this.props as { text?: Text }).text;
  }

  set text(text: Text) {
    if (this.keys.includes('text')) {
      (this.props as { text?: Text }).text = text;
    }
  }

  yBlock!: YBlock;

  _props!: SignaledProps<Props>;

  get props() {
    if (!this._props) {
      throw new Error('props is only supported in flat data model');
    }
    return this._props;
  }

  get flavour(): string {
    return this.schema.model.flavour;
  }

  get version() {
    return this.schema.version;
  }

  get children() {
    return this._childModels.value;
  }

  get store() {
    return this._store;

View on GitHub (pinned to b4c8548c09)

Solutions

  1. Access props as plain fields on the model instead (model.title, model.text) — tree-model blocks expose props directly on the instance
  2. If you own the block schema and need proxy-based access, define it with isFlatData: true and re-create existing blocks
  3. In shared code, branch on whether the flat proxy exists (check the private _props or model.keys) before touching model.props

Example fix

// before
const title = model.props.title; // throws: props is only supported in flat data model

// after — tree data model exposes props directly on the model
const title = model.title;

// or, if you own the schema and want the flat proxy:
const MyBlock = defineBlockSchema({
  flavour: 'my:block',
  isFlatData: true,
  props: () => ({ title: '' as string }),
});
Defensive patterns

Strategy: type-guard

Type guard

function hasFlatProps(model: BlockModel): boolean {
  return (model as unknown as { _props?: unknown })._props !== undefined;
}

Prevention

When it happens

Trigger: Reading model.props (or assigning model.text = new Text(...), whose setter writes through this.props) on any block whose schema does not set isFlatData: true — e.g. doc.getBlockById(id).props.title on a standard affine:paragraph block.

Common situations: Copying a snippet written for flat-data-model blocks into code that runs against tree-model blocks; upgrading BlockSuite versions where a block family changed data model; generic utility code that assumes every model exposes a props proxy.

Related errors


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