From 58a716c734e9f4ac386da44f70ba9417ab8dbb74 Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Fri, 18 Sep 2026 18:14:05 -0400 Subject: [PATCH] =?UTF-8?q?fix(editor):=20opening=20a=20thread=20on=20a=20?= =?UTF-8?q?pristine=20composer=20crashed=20the=20app=20=E2=80=94=20give=20?= =?UTF-8?q?each=20Slate=20editor=20its=20own=20initial=20value?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CustomEditor passed one module-level initialValue array to every . slate-react keys its node→path weak maps by node identity, so mounting the thread composer re-mapped the shared nodes to the new editor and the main composer threw "Unable to find the path for Slate node" on its next render, taking the whole client to the error boundary. Anything that had already edited the main editor (typing, a restored draft) replaced its nodes and masked the bug, which is why it was intermittent. Reproduced with Playwright (fresh login → room → click "N replies"): crashed every time; typing one character first avoided it. Fixed by creating the initial value per instance (useState). Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA --- src/app/components/editor/Editor.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/app/components/editor/Editor.tsx b/src/app/components/editor/Editor.tsx index ddab1cd81..e72605001 100644 --- a/src/app/components/editor/Editor.tsx +++ b/src/app/components/editor/Editor.tsx @@ -23,7 +23,13 @@ import { CustomElement } from './slate'; import * as css from './Editor.css'; import { toggleKeyboardShortcut } from './keyboard'; -const initialValue: CustomElement[] = [ +// One FRESH value per editor instance. slate-react keys its node→path weak +// maps by node object identity, so a module-level constant shared by every +// (main composer + thread composer + message editor) makes the second +// mount hijack the first editor's nodes and the first editor throws "Unable to +// find the path for Slate node" on its next render — the app-wide crash when +// opening a thread on a pristine composer (Gitea #165 / #184). +const createInitialValue = (): CustomElement[] => [ { type: BlockType.Paragraph, children: [{ text: '' }], @@ -92,6 +98,7 @@ export const CustomEditor = forwardRef( }, ref, ) => { + const [initialValue] = useState(createInitialValue); const renderElement = useCallback( (props: RenderElementProps) => , [],