From d887fdc532702f50bbaf66056e1f3a2bd56af089 Mon Sep 17 00:00:00 2001 From: Thomas Trompette Date: Thu, 23 Apr 2026 15:22:09 +0200 Subject: [PATCH] Stop throwing for event stream does not exists (#20008) Fixes https://twenty-v7.sentry.io/issues/7351816489/?environment=prod&environment=prod-eu&project=4507072499810304&query=is%3Aunresolved%20%21issue.type%3A%5Bperformance_consecutive_db_queries%2Cperformance_consecutive_http%2Cperformance_file_io_main_thread%2Cperformance_db_main_thread%2Cperformance_n_plus_one_db_queries%2Cperformance_n_plus_one_api_calls%2Cperformance_p95_endpoint_regression%2Cperformance_slow_db_query%2Cperformance_render_blocking_asset_span%2Cperformance_uncompressed_assets%2Cperformance_http_overhead%2Cperformance_large_http_payload%5D%20timesSeen%3A%3E10&referrer=issue-stream&sort=date - When an SSE event stream already exists in Redis during a reconnection, the server now checks if the caller is the rightful owner (via isAuthorized) and destroys the stale stream before creating a fresh one, instead of throwing an EVENT_STREAM_ALREADY_EXISTS error - Unauthorized callers still receive the error, preserving the security guard against hijacking --- .../subscriptions/event-stream.resolver.ts | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/packages/twenty-server/src/engine/subscriptions/event-stream.resolver.ts b/packages/twenty-server/src/engine/subscriptions/event-stream.resolver.ts index 3bddb18cef..481bd1e953 100644 --- a/packages/twenty-server/src/engine/subscriptions/event-stream.resolver.ts +++ b/packages/twenty-server/src/engine/subscriptions/event-stream.resolver.ts @@ -64,16 +64,31 @@ export class EventStreamResolver { ) { const eventStreamChannelId = eventStreamIdToChannelId(eventStreamId); - const streamData = await this.eventStreamService.getStreamData( + const existingStreamData = await this.eventStreamService.getStreamData( workspace.id, eventStreamChannelId, ); - if (isDefined(streamData)) { - throw new EventStreamException( - 'Event stream already exists', - EventStreamExceptionCode.EVENT_STREAM_ALREADY_EXISTS, - ); + if (isDefined(existingStreamData)) { + const isAuthorized = await this.eventStreamService.isAuthorized({ + streamData: existingStreamData, + authContext: { + userWorkspaceId, + apiKeyId: apiKey?.id, + }, + }); + + if (!isAuthorized) { + throw new EventStreamException( + 'Event stream already exists', + EventStreamExceptionCode.EVENT_STREAM_ALREADY_EXISTS, + ); + } + + await this.eventStreamService.destroyEventStream({ + workspaceId: workspace.id, + eventStreamChannelId, + }); } await this.eventStreamService.createEventStream({