Conversation
sendFeedback is documented to resolve only when Sentry accepted the feedback. The renderer transport returned 200 before the envelope reached the main process, so the promise succeeded for events that were never sent. Co-authored-by: Cursor <cursoragent@cursor.com>
Waiting for afterSendEvent on every renderer envelope blocked the transport buffer on ingest, and a dropped feedback never fired that hook. Only feedback waits for ingest; a pre-send drop returns status 0 instead of the 60s timeout. Co-authored-by: Cursor <cursoragent@cursor.com>
| if (category !== 'feedback' || feedbackDropWaiters.size !== 1) { | ||
| return; | ||
| } |
There was a problem hiding this comment.
Bug: When multiple feedbacks are sent concurrently, a flawed check feedbackDropWaiters.size !== 1 prevents drop notifications, causing the sendFeedback promise to hang for 60 seconds.
Severity: HIGH
Suggested Fix
The check feedbackDropWaiters.size !== 1 is flawed and should be removed. The logic should be updated to correctly notify the appropriate waiter when a feedback event is dropped, even when multiple feedbacks are being processed concurrently. This might involve iterating through the waiters and finding the correct one to call, or redesigning how waiters are managed.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: src/main/ipc.ts#L110-L112
Potential issue: A module-level `Set`, `feedbackDropWaiters`, is shared across all
concurrent feedback submissions. When multiple feedbacks are in-flight, its size becomes
greater than one. If one of these feedbacks is dropped (e.g., by `beforeSend`), the
check `feedbackDropWaiters.size !== 1` in the patched `recordDroppedEvent` handler
evaluates to true. This incorrectly prevents the `onDrop` callback from being invoked.
As a result, the corresponding `sendFeedback` promise never settles and hangs for its
full 60-second timeout instead of rejecting immediately, severely degrading user
experience in applications with multiple renderer windows.
|
Thanks for digging into this. Before we go further I'd like to understand what actually goes wrong for users. As far as I can tell, the only case where feedback really gets lost is protocol mode: if the window closes right after I'm less sure about waiting for the response from Sentry. The main process already retries and keeps an offline queue, so when the network is down the feedback still gets sent later. With this PR, |
|
Thank you for looking into this. To answer your question about what goes wrong for users: our customers were experiencing an issue where they submitted feedback, but we never received it. This was likely due to the requests being blocked by their corporate proxies. In these cases, the users believed their feedback was successfully sent (because the app UI indicated success), but it never actually reached us. Regarding the API design, as stated in the documentation, captureFeedback is intended for cases where the result doesn't need to be awaited. However, the docs explicitly state that sendFeedback "resolves only when the feedback was successfully sent to Sentry." The current renderer implementation resolves immediately without confirming delivery, which violates this documented contract. |
|
Thanks again for the report and for the PR, it made the problem very clear. I've opened #1433 with a different approach and I'd like to explain why rather than ask for a rework here. A few things in this PR would cause new problems:
#1433 keeps the The behaviour for your case is the same as here: The I'll close this in favour of #1433. Thanks for pushing on it. |
Summary
sendFeedbackis documented to resolve only when Sentry accepted the feedback, but the renderer transport always returned 200 before the envelope reached main. Protocolfetchwas not awaited, and failures were discarded.enabled: false, and an offline-queue write are not 2xx, sosendFeedbackrejects. A queued envelope may still be retried from disk later (Is it okay than sentry/electron transport drops all info from response and sentry/core base-transport tries to check it? #942).Closes #1428
Test plan
yarn test renderer-transport.test.tsELECTRON_VERSION=25.9.8 yarn e2e -t 'User Feedback'including the protocol fallback, a 64KB attachment, andwindow.close()immediately aftersendFeedbackresolvessendFeedbackrejects when the main SDK isenabled: falseor ingest returns 413sendFeedbackinstead of resolvingMade with Cursor