{"record":{"id":"e093b460ad6084b6","repo":"toeverything/AFFiNE","slug":"reactiveproxyerror-e093b4","errorCode":"ReactiveProxyError","errorMessage":"Failed to transact text! yText is not attached to a doc","messagePattern":"Failed to transact text! yText is not attached to a doc","errorType":"exception","errorClass":"BlockSuiteError","httpStatus":null,"severity":"error","filePath":"blocksuite/framework/store/src/reactive/text/text.ts","lineNumber":99,"sourceCode":"    this._deltas$ = signal(this._yText.doc ? this._yText.toDelta() : []);\n    this._yText.observe(event => {\n      const isLocal =\n        !event.transaction.origin ||\n        !this._yText.doc ||\n        event.transaction.origin instanceof Y.UndoManager ||\n        event.transaction.origin.proxy\n          ? true\n          : event.transaction.origin === this._yText.doc.clientID;\n      this._length$.value = this._yText.length;\n      this._deltas$.value = this._yText.toDelta();\n      this._onChange?.(this._yText, isLocal);\n    });\n  }\n\n  private _transact(callback: () => void) {\n    const doc = this._yText.doc;\n    if (!doc) {\n      throw new BlockSuiteError(\n        ErrorCode.ReactiveProxyError,\n        'Failed to transact text! yText is not attached to a doc'\n      );\n    }\n    doc.transact(() => {\n      callback();\n    }, doc.clientID);\n  }\n\n  /**\n   * Apply a delta to the text.\n   *\n   * @param delta - The delta to apply.\n   *\n   * @example\n   * ```ts\n   * const text = new Text('Hello, world!');\n   * text.applyDelta([{insert: ' blocksuite', attributes: { bold: true }}]);","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/blocksuite/framework/store/src/reactive/text/text.ts#L81-L117","documentation":"Every mutating Text method (insert, delete, format, replace, clear, split, join) funnels through `_transact`, which requires `yText.doc`. The Text constructor deliberately accepts unattached input — `new Text('hi')` creates a standalone `Y.Text` — so calling any mutation before that Y.Text is integrated into a Y.Doc throws this error.","triggerScenarios":"`const t = new Text('hello'); t.insert('!', 5);`; `new Text(deltaArray).format(0, 1, {bold: true})`; `new Text(detachedYText).delete(0, 1)`; any mutation after the owning doc is destroyed.","commonSituations":"Building a Text from a plain string or delta for later attachment, then editing it too early; block-level text created before the block model is mounted in the doc; post-teardown editing callbacks.","solutions":["Attach before mutating: `const t = new Text('hi'); ydoc.getMap('texts').set('t', t.yText); t.insert('!', 2);`","Or construct from an already-attached Y.Text: `new Text(ydoc.getText('t'))`","Check `text.yText.doc !== null` before calling any mutation method","For never-synced scratch strings, keep a plain string and build the Text after attachment"],"exampleFix":"// before\nconst title = new Text('draft');\ntitle.insert('!', 6); // throws: yText has no doc\n\n// after\nconst title = new Text('draft');\nydoc.getMap('blocks').set('title', title.yText); // integrate\ntitle.insert('!', 6);","handlingStrategy":"validation","validationCode":"if (text.yText.doc === null) {\n  ydoc.getMap('texts').set('t', text.yText); // integrate before editing\n}\ntext.insert('!', text.length);","typeGuard":"const isEditableText = (t: Text): boolean => t.yText.doc !== null;","tryCatchPattern":"try {\n  text.insert(content, index);\n} catch (e) {\n  if (e instanceof BlockSuiteError && e.code === ErrorCode.ReactiveProxyError && e.message.includes('not attached')) {\n    ydoc.getMap('texts').set('t', text.yText);\n    text.insert(content, index); // retry once attached\n  } else throw e;\n}","preventionTips":["Attach the Y.Text to a doc (or construct Text from an attached Y.Text) before any mutation","Check text.yText.doc !== null before insert/delete/format/replace/clear","Keep unattached scratch strings as plain strings; build Text only after integration"],"tags":["yjs","y-doc","rich-text","text","blocksuite"],"backgroundTag":"yjs-type-not-attached-to-doc","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"}