From bb9434d3075740aa7d5e2b0d4d355b76c6499890 Mon Sep 17 00:00:00 2001 From: Jakub Wolniewicz <4850809+frizikk@users.noreply.github.com> Date: Tue, 28 Jul 2026 14:18:30 +0200 Subject: [PATCH] fix(desktop): match current assistant-ui lookup errors --- .../src/components/error-boundary.test.tsx | 20 +++++++++++-------- .../desktop/src/components/error-boundary.tsx | 8 ++++---- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/apps/desktop/src/components/error-boundary.test.tsx b/apps/desktop/src/components/error-boundary.test.tsx index 133de61687817..549ab4aad9c10 100644 --- a/apps/desktop/src/components/error-boundary.test.tsx +++ b/apps/desktop/src/components/error-boundary.test.tsx @@ -3,7 +3,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { ErrorBoundary } from './error-boundary' -const TAP_LOOKUP_ERROR = new Error('tapClientLookup: Index 6 out of bounds (length: 2)') +const CURRENT_LOOKUP_ERROR = new Error('useClientLookup: Index 6 out of bounds (length: 2)') const RELOAD_WINDOW = { name: 'Reload window', role: 'button' } as const function makeBomb(box: { error: Error | null }) { @@ -17,9 +17,9 @@ function makeBomb(box: { error: Error | null }) { } const recoveryWarningCount = (calls: unknown[][]) => - calls.filter(call => call.some(value => String(value).includes('auto-recovering from tapClientLookup'))).length + calls.filter(call => call.some(value => String(value).includes('auto-recovering from assistant-ui lookup'))).length -describe('ErrorBoundary tapClientLookup recovery', () => { +describe('ErrorBoundary assistant-ui lookup recovery', () => { beforeEach(() => { vi.useFakeTimers() vi.spyOn(console, 'error').mockImplementation(() => undefined) @@ -31,9 +31,13 @@ describe('ErrorBoundary tapClientLookup recovery', () => { vi.restoreAllMocks() }) - it('recovers the root boundary after a transient lookup race clears', () => { + it.each([ + ['the current useClientLookup error', CURRENT_LOOKUP_ERROR], + ['the legacy tapClientLookup error', new Error('tapClientLookup: Index 6 out of bounds (length: 2)')], + ['the legacy tapClientResource error', new Error('tapClientResource: Index 6 out of bounds (length: 2)')] + ])('recovers the root boundary after %s clears', (_label, error) => { const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined) - const box: { error: Error | null } = { error: TAP_LOOKUP_ERROR } + const box: { error: Error | null } = { error } const Bomb = makeBomb(box) render( @@ -52,7 +56,7 @@ describe('ErrorBoundary tapClientLookup recovery', () => { it('stops retrying a persistent lookup error after the recovery budget is exhausted', () => { const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined) - const box: { error: Error | null } = { error: TAP_LOOKUP_ERROR } + const box: { error: Error | null } = { error: CURRENT_LOOKUP_ERROR } const Bomb = makeBomb(box) render( @@ -72,7 +76,7 @@ describe('ErrorBoundary tapClientLookup recovery', () => { it('does not auto-recover the same error in a scoped boundary', () => { const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined) - const Bomb = makeBomb({ error: TAP_LOOKUP_ERROR }) + const Bomb = makeBomb({ error: CURRENT_LOOKUP_ERROR }) render(
scoped fallback
} label="thread"> @@ -87,7 +91,7 @@ describe('ErrorBoundary tapClientLookup recovery', () => { }) it.each([ - ['a renamed lookup error', new Error('useClientLookup: Index 6 out of bounds (length: 2)')], + ['a non-bounds lookup error', new Error('useClientLookup: Key "missing" not found')], ['an unrelated render error', new Error('some unrelated application error')] ])('does not auto-recover %s at root', (_label, error) => { const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined) diff --git a/apps/desktop/src/components/error-boundary.tsx b/apps/desktop/src/components/error-boundary.tsx index 10fd0d614c06f..5f5a8eaef4fd4 100644 --- a/apps/desktop/src/components/error-boundary.tsx +++ b/apps/desktop/src/components/error-boundary.tsx @@ -23,11 +23,11 @@ interface ErrorBoundaryState { // Some assistant-ui lookup races escape the message-local boundary and reach // the root. Retry only that exact transient error class, never arbitrary render // failures, and cap retries so a persistent failure still exposes the fallback. -const TAP_CLIENT_LOOKUP_ERROR = /^tapClientLookup: Index \d+\s+out of bounds \(length:\s*\d+\)$/i +const ASSISTANT_UI_LOOKUP_ERROR = /(useClientLookup|tapClient(Lookup|Resource)).*out of bounds/i const MAX_AUTO_RECOVERIES = 3 const AUTO_RECOVERY_WINDOW_MS = 5_000 -const isTransientTapClientLookupError = (error: Error): boolean => TAP_CLIENT_LOOKUP_ERROR.test(error.message) +const isTransientAssistantUiLookupError = (error: Error): boolean => ASSISTANT_UI_LOOKUP_ERROR.test(error.message) export class ErrorBoundary extends Component { state: ErrorBoundaryState = { error: null } @@ -44,8 +44,8 @@ export class ErrorBoundary extends Component