@@ -129,13 +129,66 @@ const Editor = ({
129129 cleanupProviders ( ) ;
130130 } , [ ] ) ;
131131
132+ // Handle Monaco disposal errors gracefully - suppress instead of remounting
133+ useEffect ( ( ) => {
134+ const handleMonacoError = ( event : ErrorEvent ) => {
135+ const message = event . error ?. message || "" ;
136+ if (
137+ message . includes ( "InstantiationService has been disposed" ) ||
138+ message . includes ( "domNode" ) ||
139+ message . includes ( "renderText" ) ||
140+ message . includes ( "AnimationFrameQueueItem" )
141+ ) {
142+ // Suppress Monaco cleanup errors - they're harmless during layout changes
143+ console . debug ( "Monaco cleanup error suppressed:" , message ) ;
144+ event . preventDefault ( ) ;
145+ event . stopPropagation ( ) ;
146+ return false ;
147+ }
148+ return true ;
149+ } ;
150+
151+ const handleUnhandledRejection = ( event : PromiseRejectionEvent ) => {
152+ const message = event . reason ?. message || "" ;
153+ if (
154+ message . includes ( "InstantiationService has been disposed" ) ||
155+ message . includes ( "domNode" ) ||
156+ message . includes ( "renderText" )
157+ ) {
158+ // Suppress Monaco cleanup errors in promises
159+ console . debug ( "Monaco cleanup promise error suppressed:" , message ) ;
160+ event . preventDefault ( ) ;
161+ return false ;
162+ }
163+ return true ;
164+ } ;
165+
166+ window . addEventListener ( "error" , handleMonacoError , true ) ;
167+ window . addEventListener ( "unhandledrejection" , handleUnhandledRejection ) ;
168+
169+ return ( ) => {
170+ window . removeEventListener ( "error" , handleMonacoError , true ) ;
171+ window . removeEventListener ( "unhandledrejection" , handleUnhandledRejection ) ;
172+ } ;
173+ } , [ ] ) ;
174+
132175 // Cleanup on unmount
133176 useEffect ( ( ) => {
134177 return ( ) => {
135178 cleanupMonaco ( ) ;
136179 } ;
137180 } , [ cleanupMonaco ] ) ;
138181
182+ // Track if component is mounted to prevent layout operations after unmount
183+ const isMountedRef = useRef ( true ) ;
184+
185+ useEffect ( ( ) => {
186+ isMountedRef . current = true ;
187+ return ( ) => {
188+ isMountedRef . current = false ;
189+ } ;
190+ } , [ ] ) ;
191+
139192 const onMount = useCallback (
140193 ( editor : any , mon : any , t : Tools ) => {
141194 editorRef . current = editor ;
@@ -159,6 +212,58 @@ const Editor = ({
159212 }
160213 } ;
161214
215+ // Safe layout wrapper - only layout if mounted
216+ const originalLayout = editor . layout . bind ( editor ) ;
217+ editor . layout = function ( ...args : any [ ] ) {
218+ if ( ! isMountedRef . current ) {
219+ console . debug ( "Skipped layout call on unmounted editor" ) ;
220+ return ;
221+ }
222+ try {
223+ originalLayout ( ...args ) ;
224+ } catch ( error : any ) {
225+ if (
226+ ! error . message ?. includes ( "InstantiationService has been disposed" ) &&
227+ ! error . message ?. includes ( "domNode" )
228+ ) {
229+ throw error ;
230+ }
231+ console . debug ( "Suppressed layout error during cleanup" ) ;
232+ }
233+ } ;
234+
235+ // Patch the editor's internal rendering to prevent domNode errors
236+ // This is a deep patch to prevent errors from bubbling up
237+ try {
238+ const editorInternal = ( editor as any ) . _view ;
239+ if ( editorInternal && editorInternal . _renderingCoordinator ) {
240+ const coordinator = editorInternal . _renderingCoordinator ;
241+ const originalOnRenderScheduled = coordinator . _onRenderScheduled ;
242+ if ( originalOnRenderScheduled ) {
243+ coordinator . _onRenderScheduled = function ( this : any ) {
244+ if ( ! isMountedRef . current || ! editorRef . current ) {
245+ console . debug ( "Skipped render on unmounted editor" ) ;
246+ return ;
247+ }
248+ try {
249+ originalOnRenderScheduled . call ( this ) ;
250+ } catch ( error : any ) {
251+ if (
252+ error . message ?. includes ( "domNode" ) ||
253+ error . message ?. includes ( "renderText" )
254+ ) {
255+ console . debug ( "Suppressed Monaco rendering error:" , error . message ) ;
256+ return ;
257+ }
258+ throw error ;
259+ }
260+ } ;
261+ }
262+ }
263+ } catch ( e ) {
264+ console . debug ( "Could not patch Monaco rendering coordinator (non-critical)" ) ;
265+ }
266+
162267 // Monaco Editor markers will automatically show error tooltips on hover
163268 // No need for custom hover provider as it causes duplicates
164269
@@ -261,7 +366,16 @@ const Editor = ({
261366 const editor = editorRef . current ;
262367 if ( ! editor ) return ;
263368
264- const monacoErrors : any [ ] = validate ( t ) ( editor ?. getValue ( ) || str ) . map ( error => {
369+ // Check if model exists before parsing
370+ const model = editor ?. getModel ( ) ;
371+ if ( ! model ) {
372+ console . debug ( "parseContent: model not ready yet" ) ;
373+ return ;
374+ }
375+
376+ // Use provided string or get value from editor
377+ const content = str !== undefined ? str : editor . getValue ( ) ;
378+ const monacoErrors : any [ ] = validate ( t ) ( content ) . map ( error => {
265379 return {
266380 startLineNumber : error . startLine ,
267381 startColumn : error . startCol ,
@@ -273,15 +387,14 @@ const Editor = ({
273387 : monacoRef . current ?. editor ?. MarkerSeverity ?. Error || 8
274388 } ;
275389 } ) ;
276- const model = editor ?. getModel ( ) ;
277- if ( model ) {
278- if ( ! isTestEnvironment && monacoRef . current ?. editor ) {
279- // Clear existing markers first
280- monacoRef . current . editor . setModelMarkers ( model , "owner" , [ ] ) ;
281- // Set new markers
282- monacoRef . current . editor . setModelMarkers ( model , "owner" , monacoErrors ) ;
283- }
390+
391+ if ( ! isTestEnvironment && monacoRef . current ?. editor ) {
392+ // Clear existing markers first
393+ monacoRef . current . editor . setModelMarkers ( model , "owner" , [ ] ) ;
394+ // Set new markers
395+ monacoRef . current . editor . setModelMarkers ( model , "owner" , monacoErrors ) ;
284396 }
397+
285398 if ( onListErrors ) {
286399 onListErrors (
287400 monacoErrors . map ( error => {
0 commit comments