{"record":{"id":"96a1011cb5a8c8cc","repo":"toeverything/AFFiNE","slug":"reactiveproxyerror","errorCode":"ReactiveProxyError","errorMessage":"flatY2Native does not support Y.Map as value of Y.Map","messagePattern":"flatY2Native does not support Y\\.Map as value of Y\\.Map","errorType":"exception","errorClass":"BlockSuiteError","httpStatus":null,"severity":"error","filePath":"blocksuite/framework/store/src/reactive/flat-native-y/initialize.ts","lineNumber":37,"sourceCode":"}: InitializeDataOptions): UnRecord => {\n  const root: UnRecord = {};\n  Array.from(yMap.entries()).forEach(([key, value]) => {\n    if (key.startsWith('sys')) {\n      return;\n    }\n    const keys = keyWithoutPrefix(key).split('.');\n    const firstKey = keys[0];\n\n    let finalData = value;\n    if (Boxed.is(value)) {\n      finalData = transform(firstKey, new Boxed(value), value);\n    } else if (value instanceof YArray) {\n      finalData = transform(firstKey, value.toArray(), value);\n    } else if (value instanceof YText) {\n      const next = new Text(value);\n      finalData = transform(firstKey, next, value);\n    } else if (value instanceof YMap) {\n      throw new BlockSuiteError(\n        BlockSuiteError.ErrorCode.ReactiveProxyError,\n        'flatY2Native does not support Y.Map as value of Y.Map'\n      );\n    } else {\n      finalData = transform(firstKey, value, value);\n    }\n    const allLength = keys.length;\n    void keys.reduce((acc: UnRecord, key, index) => {\n      if (!acc[key] && index !== allLength - 1) {\n        const path = keys.slice(0, index + 1).join('.');\n        const data = getProxy({} as UnRecord, root, path);\n        acc[key] = data;\n      }\n      if (index === allLength - 1) {\n        acc[key] = finalData;\n      }\n      return acc[key] as UnRecord;\n    }, root);","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/blocksuite/framework/store/src/reactive/flat-native-y/initialize.ts#L19-L55","documentation":"In the flat reactive layer (ReactiveFlatYMap), props are stored as flattened dot-notation keys (prop:a.b) and initializeData only knows how to materialize Boxed values, Y.Array, Y.Text and plain scalars. A Y.Map nested as a prop value has no flat representation, so hydration throws ReactiveProxyError instead of producing a broken proxy.","triggerScenarios":"A flat-data-model block whose prop:* entry holds a Y.Map — typically data written by the tree-model path (native2Y turns nested objects into Y.Map, crud.ts:115) and then read through the flat layer, or raw Yjs writes putting a Y.Map under a prop key.","commonSituations":"Switching a block family from the tree data model to isFlatData while old docs still hold nested Y.Map props; import scripts reusing tree-model serialization for flat blocks; two features writing the same flavour through different data models.","solutions":["Model nested data as flattened dot-notation keys (as addBlock does for isFlatData blocks via the recursive run() at crud.ts:100-110), not nested Y.Maps","Use supported containers for structured values: Y.Array (arrays), Y.Text (rich text), Boxed (opaque values)","Do not point the same flavour at both data models — pick tree or flat and keep all writers consistent","Migrate existing props: walk the Y.Map and flatten each entry into prop:parent.child keys"],"exampleFix":"// before — nested Y.Map under a flat-model prop\nyBlock.set('prop:style', new Y.Map([['color', 'red']]));\n// hydration -> flatY2Native does not support Y.Map as value of Y.Map\n\n// after — flatten to dot-notation keys\nyBlock.set('prop:style.color', 'red');\n// or model it as a supported type\nyBlock.set('prop:tags', new Y.Array(['a', 'b']));","handlingStrategy":"type-guard","validationCode":"import * as Y from 'yjs';\nfunction isFlatSafeValue(value: unknown): boolean {\n  return (\n    value === null ||\n    ['string', 'number', 'boolean'].includes(typeof value) ||\n    value instanceof Y.Array ||\n    value instanceof Y.Text\n  );\n}\n\n// before writing a prop on a flat-model block:\nif (!isFlatSafeValue(value)) {\n  throw new Error('flatten the value into dot-notation keys instead');\n}","typeGuard":"const isFlatSafeValue = (v: unknown): boolean =>\n  v === null || ['string', 'number', 'boolean'].includes(typeof v) ||\n  v instanceof Y.Array || v instanceof Y.Text;","tryCatchPattern":"try {\n  doc.load();\n} catch (e) {\n  if (e instanceof BlockSuiteError && e.code === ErrorCode.ReactiveProxyError) {\n    // a prop holds a Y.Map: flatten it into prop:a.b keys, then reload\n  }\n}","preventionTips":["Choose one data model per flavour and never mix writers","Store nested objects as flattened dot-notation keys, arrays as Y.Array, rich text as Y.Text, opaque values as Boxed","Lint raw yBlock.set('prop:...', new Y.Map(...)) calls in reviews"],"tags":["blocksuite","flat-data-model","yjs","reactive","props"],"backgroundTag":"unsupported-data-type","analyzedSha":"b4c8548c09da21b2898443559a5b846f0ccf5dd8","analyzedAt":"2026-08-18T21:16:52.546Z","contentChangedAt":"2026-08-18T21:16:52.546Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}