@@ -776,6 +776,84 @@ describe('SentryEventWorker', () => {
776776 } ) ;
777777 } ) ;
778778
779+ describe ( 'Binary data handling' , ( ) => {
780+ it ( 'should handle envelope with replay_recording binary data without crashing' , async ( ) => {
781+ // This is the actual problematic envelope that was causing crashes
782+ const problematicEvent = {
783+ projectId : '621601f4a010d35c68b4625a' ,
784+ payload : {
785+ envelope :
786+ 'eyJldmVudF9pZCI6IjRjNDBmZWU3MzAxOTRhOTg5NDM5YTg2YmY3NTYzNDExIiwic2VudF9hdCI6IjIwMjUtMDgtMjlUMTA6NTk6MjkuOTUyWiIsInNkayI6eyJuYW1lIjoic2VudHJ5LmphdmFzY3JpcHQucmVhY3QiLCJ2ZXJzaW9uIjoiOS4xMC4xIn19CnsidHlwZSI6InJlcGxheV9ldmVudCJ9CnsidHlwZSI6InJlcGxheV9ldmVudCIsInJlcGxheV9zdGFydF90aW1lc3RhbXAiOjE3NTY0NjQ4NjguNDA0LCJ0aW1lc3RhbXAiOjE3NTY0NjUxNjkuOTQ3LCJlcnJvcl9pZHMiOltdLCJ0cmFjZV9pZHMiOlsiZjlkMGE5NjdjZjM2NDFkYzlhODE5NjVjMzY4ZDQ3MzMiXSwidXJscyI6W10sInJlcGxheV9pZCI6IjRjNDBmZWU3MzAxOTRhOTg5NDM5YTg2YmY3NTYzNDExIiwic2VnbWVudF9pZCI6MywicmVwbGF5X3R5cGUiOiJzZXNzaW9uIiwicmVxdWVzdCI6eyJ1cmwiOiJodHRwczovL3ZpZXcueXN0dXR5LnJ1L2dyb3VwIyVEMCU5QyVEMCU5Qy0yMSIsImhlYWRlcnMiOnsiUmVmZXJlciI6Imh0dHBzOi8vYXdheS52ay5jb20vIiwiVXNlci1BZ2VudCI6Ik1vemlsbGEvNS4wIChpUGhvbmU7IENQVSBpUGhvbmUgT1MgMThfNSBsaWtlIE1hYyBPUyBYKSBBcHBsZVdlYktpdC82MDUuMS4xNSAoS0hUTUwsIGxpa2UgR2Vja28pIFZlcnNpb24vMTguNSBNb2JpbGUvMTVFMTQ4IFNhZmFyaS82MDQuMSJ9fSwiZXZlbnRfaWQiOiI0YzQwZmVlNzMwMTk0YTk4OTQzOWE4NmJmNzU2MzQxMSIsImVudmlyb25tZW50IjoicHJvZHVjdGlvbiIsInNkayI6eyJpbnRlZ3JhdGlvbnMiOlsiSW5ib3VuZEZpbHRlcnMiLCJGdW5jdGlvblRvU3RyaW5nIiwiQnJvd3NlckFwaUVycm9ycyIsIkJyZWFkY3J1bWJzIiwiR2xvYmFsSGFuZGxlcnMiLCJMaW5rZWRFcnJvcnMiLCJEZWR1cGUiLCJIdHRwQ29udGV4dCIsIkJyb3dzZXJTZXNzaW9uIiwiQnJvd3NlclRyYWNpbmciLCJSZXBsYXkiXSwibmFtZSI6InNlbnRyeS5qYXZhc2NyaXB0LnJlYWN0IiwidmVyc2lvbiI6IjkuMTAuMSJ9LCJjb250ZXh0cyI6eyJyZWFjdCI6eyJ2ZXJzaW9uIjoiMTcuMC4yIn19LCJ0cmFuc2FjdGlvbiI6Ii9ncm91cCIsInBsYXRmb3JtIjoiamF2YXNjcmlwdCJ9CnsidHlwZSI6InJlcGxheV9yZWNvcmRpbmciLCJsZW5ndGgiOjM0M30KeyJzZWdtZW50X2lkIjozfQp4nJVRwWrCQBD9lzmniQlRMbe2hiJtUTQeikhYkzEJJNnt7mxLKF6JH+UndVIP0tIK3dMy896bN/M2H0CdQoiGDlDVoCHRKIj88XAUjoaDwHeDcOxALkhAxFhRQAQK9V7qRrQZrpRowQElulqKvIdIpoNGI63O0N0jZSUDcjSZrhRVsuV2SaRM5HlFcSNU5XaGLHWutp7xTFZibmv03vzLv9DSKu90PB1vAp/V2KWm5G+72Oa/dQM3HIeXZRqkUrJneIiTsyhZcy9zvkYwGDi8xKtljR5aoshRG/4eHEiZ+CXwLnRbtQWXN7BePqWrx9liEU9he2AUn0DJ1rDYf+kO3M2nL+nidrmK02T2HM/XSa/ZP+dqXv5o4k7C0c+8dprnZ9o2u+9RXRE4D+HY9sLWxLRMEBZSd1y0lburrQa2s/0EaMG6/Q==' ,
787+ } ,
788+ catcherType : 'external/sentry' as const ,
789+ timestamp : 1756465170 ,
790+ } ;
791+
792+ // Before the fix, this would throw: SyntaxError: Unexpected token ♦ in JSON at position 0
793+ // After the fix, it should handle gracefully by filtering out binary data
794+ await worker . handle ( problematicEvent ) ;
795+
796+ // Should not crash and should not send any tasks (since no event items remain after filtering)
797+ expect ( mockedAmqpChannel . sendToQueue ) . not . toHaveBeenCalled ( ) ;
798+ } ) ;
799+
800+ it ( 'should process mixed envelope with both event and replay_recording items' , async ( ) => {
801+ // Create Sentry envelope format: each line is a separate JSON object
802+ const envelopeLines = [
803+ // Envelope header
804+ JSON . stringify ( {
805+ /* eslint-disable @typescript-eslint/naming-convention */
806+ event_id : '4c40fee730194a989439a86bf75634111' ,
807+ sent_at : '2025-08-29T10:59:29.952Z' ,
808+ /* eslint-enable @typescript-eslint/naming-convention */
809+ sdk : { name : 'sentry.javascript.react' , version : '9.10.1' } ,
810+ } ) ,
811+ // Event item header
812+ JSON . stringify ( { type : 'event' } ) ,
813+ // Event item payload
814+ JSON . stringify ( { message : 'Test event' , level : 'error' } ) ,
815+ // Replay event item header - should be filtered out
816+ JSON . stringify ( { type : 'replay_event' } ) ,
817+ // Replay event item payload - should be filtered out
818+ JSON . stringify ( {
819+ /* eslint-disable @typescript-eslint/naming-convention */
820+ replay_id : 'test-replay' ,
821+ segment_id : 1 ,
822+ /* eslint-enable @typescript-eslint/naming-convention */
823+ } ) ,
824+ // Replay recording item header - should be filtered out
825+ JSON . stringify ( { type : 'replay_recording' , length : 343 } ) ,
826+ // Replay recording binary payload - should be filtered out
827+ 'binary-data-here-that-is-not-json' ,
828+ ] ;
829+
830+ const envelopeString = envelopeLines . join ( '\n' ) ;
831+
832+ await worker . handle ( {
833+ payload : {
834+ envelope : b64encode ( envelopeString ) ,
835+ } ,
836+ projectId : '621601f4a010d35c68b4625a' ,
837+ catcherType : 'external/sentry' ,
838+ } ) ;
839+
840+ // Should only process the event item, not the replay items
841+ expect ( mockedAmqpChannel . sendToQueue ) . toHaveBeenCalledTimes ( 1 ) ;
842+
843+ const addedTaskPayload = getAddTaskPayloadFromLastCall ( ) ;
844+ expect ( addedTaskPayload ) . toMatchObject ( {
845+ payload : expect . objectContaining ( {
846+ addons : {
847+ sentry : {
848+ message : 'Test event' ,
849+ level : 'error' ,
850+ } ,
851+ } ,
852+ } ) ,
853+ } ) ;
854+ } ) ;
855+ } ) ;
856+
779857 describe ( 'envelope parsing' , ( ) => {
780858 const event = {
781859 projectId : '67ed371b4196dcbd73537c64' ,
0 commit comments