Skip to content

Conversation

@gauthierpetetin
Copy link
Contributor

@gauthierpetetin gauthierpetetin commented Oct 30, 2025

Description

This PR is an AI-generated fix aiming to fix the #1 error in Sentry (3.8M occurrences/month) by adding graceful shutdown handlers to extension context streams, preventing "ERR_STREAM_PREMATURE_CLOSE" errors.

The error was initially discussed in this Slack thread.

Disclaimer

Since we haven't found a reliable way to manually reproduce these "Premature close" errors, there's no "before/after proof" that this PR fixes it.

Problem

When underlying transport streams (e.g., WindowPostMessageStream, ExtensionPortStream) close or end abruptly—during page navigation, tab closure, or extension disconnection—the ObjectMultiplex instances in extension context do not gracefully shut down. This results in "Premature close" errors being thrown by the stream pipeline.

Solution

Added graceful shutdown handlers to extension context streams that:

  1. Listen for transport termination: Attach once('close') and once('end') listeners to underlying transport streams
  2. Proactively close muxes: When transport terminates, check if mux is still open (!destroyed && !writableEnded) and call mux.end() before pipeline error detection kicks in
  3. Prevent error propagation: By closing gracefully, we avoid "ERR_STREAM_PREMATURE_CLOSE" errors in the pipeline

Key Design Decision: Page Context vs Extension Context

Why handlers are ONLY in extension context streams:

Context Files Needs Handlers? Reason
Page Context inpage.js NO Browser automatically destroys the entire script execution context on navigation. Adding handlers can actually CAUSE disconnection errors during rapid navigation.
Extension Context provider-stream.ts
phishing-stream.ts
cookie-handler-stream.ts
YES Extension context persists across page navigations. Muxes remain active when transports disconnect, causing "Premature close" errors without explicit cleanup.

This approach mirrors the solution in #33470 for CAIP streams.

Open in GitHub Codespaces

Changelog

CHANGELOG entry: Fixed "Premature close" stream errors in extension context by adding graceful shutdown handlers

Related issues

Fixes: #26337
Fixes: #35241
Fixes: #21078

Manual testing steps

(disclaimer: the error is hard to reproduce, even with these manual testing steps)

  1. Open a dapp page connected to MetaMask (e.g., https://metamask.github.io/test-dapp/)
  2. Rapidly navigate between pages multiple times or close/reopen tabs
  3. Open DevTools Console and check for errors
  4. Open Extension Background Console: chrome://extensions → MetaMask → "service worker"
  5. Verify no "Premature close" errors appear during page navigation
  6. Test deep link navigation: Navigate to chrome-extension://{extension-id}/home.html#link?u=/buy and verify it redirects cleanly without errors

Expected: Clean shutdowns with no "Premature close" errors in console

Screenshots/Recordings

Before

  • "Premature close" errors appear in extension background console during page navigation
  • Sentry reports 3.8M occurrences per month

After

  • Extension context streams shut down gracefully
  • No "Premature close" errors during normal operations
  • E2E tests pass (including deep-link tests that navigate rapidly)

Pre-merge author checklist

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Note

Add graceful shutdown handlers to extension-context multiplexers for provider, phishing, and cookie-handler streams, plus tests; clarify no handlers in page-context in inpage.

  • Streams (extension context):
    • Graceful shutdown handlers: End muxes on underlying transport close/end to avoid ERR_STREAM_PREMATURE_CLOSE in:
      • app/scripts/streams/provider-stream.ts (pageMux, extensionMux)
      • app/scripts/streams/phishing-stream.ts (phishingPageMux, phishingExtMux)
      • app/scripts/streams/cookie-handler-stream.ts (cookieHandlerPageMux, cookieHandlerMux)
    • Logging/notifications: Preserve existing pipeline callbacks; continue logging via logStreamDisconnectWarning and sending METAMASK_STREAM_FAILURE where applicable.
  • Inpage (page context):
    • app/scripts/inpage.js: Add documentation explaining why graceful shutdown handlers are not added in page context.
  • Tests:
    • Add filter tests to assert unconditional logging on pipeline completion/error:
      • provider-stream.filter.test.ts
      • phishing-stream.filter.test.ts
      • cookie-handler-stream.filter.test.ts

Written by Cursor Bugbot for commit e72ec5e. This will update automatically on new commits. Configure here.

@gauthierpetetin gauthierpetetin self-assigned this Oct 30, 2025
@gauthierpetetin gauthierpetetin added the team-extension-platform Extension Platform team label Oct 30, 2025
@github-actions
Copy link
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@metamaskbot
Copy link
Collaborator

📊 Page Load Benchmark Results

Current Commit: d5f5e65 | Date: 10/30/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.05s (±41ms) 🟡 | historical mean value: 1.05s ⬆️ (historical data)
  • domContentLoaded-> current mean value: 735ms (±37ms) 🟢 | historical mean value: 732ms ⬆️ (historical data)
  • firstContentfulPaint-> current mean value: 78ms (±14ms) 🟢 | historical mean value: 77ms ⬆️ (historical data)
📈 Detailed Results
Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.05s 41ms 1.02s 1.35s 1.08s 1.35s
domContentLoaded 735ms 37ms 707ms 1.00s 758ms 1.00s
firstPaint 78ms 14ms 60ms 204ms 88ms 204ms
firstContentfulPaint 78ms 14ms 60ms 204ms 88ms 204ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms

Results generated automatically by MetaMask CI

@metamaskbot
Copy link
Collaborator

Builds ready [d5f5e65]
UI Startup Metrics (1269 ± 99 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup1269109217259913151433
load108794314579011371230
domContentLoaded108193814378911311222
domInteractive19134871839
firstPaint55489146843710611206
backgroundConnect2282162608232243
firstReactRender29195683444
getState22893142346
initialActions707210823
loadScripts859700119388910996
setupStore1062631118
numNetworkReqs96337630
BrowserifyPower User HomeuiStartup22401812318548328903185
load1183944169927415981699
domContentLoaded1175935169227515941692
domInteractive291668174268
firstPaint583192166845310361668
backgroundConnect27123353270282532
firstReactRender27233233032
getState17712624026189240
initialActions1016515965
loadScripts930706142525613371425
setupStore1382751427
numNetworkReqs430200753197674753
WebpackStandard HomeuiStartup8547401138738691051
load63858992870648864
domContentLoaded63158291269641854
domInteractive15115481439
firstPaint17957884173179711
backgroundConnect23125992545
firstReactRender27174073233
getState1252341418
initialActions3015348
loadScripts62858090267639844
setupStore1061631214
numNetworkReqs96358833
WebpackPower User HomeuiStartup17171264252239922552522
load77463012262009801226
domContentLoaded72761610761558531076
domInteractive19133882938
firstPaint46012810793648561079
backgroundConnect14721461168418461
firstReactRender26234352643
getState15410620220162202
initialActions51368536
loadScripts72161310661498431066
setupStore1462872328
numNetworkReqs389218733163575733
FirefoxBrowserifyStandard HomeuiStartup14811308190610815351676
load1261112814617613151408
domContentLoaded1261112714617613151406
domInteractive1153623142127212
firstPaint------
backgroundConnect4526145185275
firstReactRender26225862644
getState74737812
initialActions511841837
loadScripts1233110714337512741380
setupStore127186181215
numNetworkReqs96306825
BrowserifyPower User HomeuiStartup29412360364841933663648
load15091279188817416321888
domContentLoaded15081278188817416311888
domInteractive1789637178233371
firstPaint------
backgroundConnect23156504142333504
firstReactRender42315795057
getState14411023630157236
initialActions9144111544
loadScripts14461220176515915671765
setupStore3991143161114
numNetworkReqs26615239170317391
WebpackStandard HomeuiStartup16301461190911016931862
load1393122416559414641558
domContentLoaded1393122416549414641558
domInteractive1103539760120231
firstPaint------
backgroundConnect4925143215586
firstReactRender322398153175
getState9416016814
initialActions4140447
loadScripts1365120116259314361538
setupStore1368391322
numNetworkReqs96337826
WebpackPower User HomeuiStartup29402341451668934424516
load16191388216020317412160
domContentLoaded16191388216020317412160
domInteractive1418026153190261
firstPaint------
backgroundConnect2663212463872301246
firstReactRender423076145076
getState1396724645163246
initialActions9166151066
loadScripts15511341188515416381885
setupStore34102385431238
numNetworkReqs281132661178446661
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 68 Bytes (0%)
  • ui: 0 Bytes (0%)
  • common: 10 Bytes (0%)

@metamaskbot
Copy link
Collaborator

📊 Page Load Benchmark Results

Current Commit: 64e70d8 | Date: 10/30/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.07s (±64ms) 🟡 | historical mean value: 1.05s ⬆️ (historical data)
  • domContentLoaded-> current mean value: 741ms (±77ms) 🟢 | historical mean value: 732ms ⬆️ (historical data)
  • firstContentfulPaint-> current mean value: 86ms (±46ms) 🟢 | historical mean value: 77ms ⬆️ (historical data)
📈 Detailed Results
Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.07s 64ms 970ms 1.44s 1.15s 1.44s
domContentLoaded 741ms 77ms 674ms 1.39s 793ms 1.39s
firstPaint 86ms 46ms 64ms 540ms 96ms 540ms
firstContentfulPaint 86ms 46ms 64ms 540ms 96ms 540ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms

Results generated automatically by MetaMask CI

@metamaskbot
Copy link
Collaborator

Builds ready [64e70d8]
UI Startup Metrics (1280 ± 71 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup1280114414237113241393
load109397312316511371205
domContentLoaded108797112246411321192
domInteractive20145381944
firstPaint65899123243811041177
backgroundConnect2302192597234243
firstReactRender30185183547
getState2175582434
initialActions71648822
loadScripts86374599863907972
setupStore1162941322
numNetworkReqs96327630
BrowserifyPower User HomeuiStartup23341818402169532134021
load1219945216637116292166
domContentLoaded1210938213536616222135
domInteractive34161062558106
firstPaint819183217549610442175
backgroundConnect28222461099287610
firstReactRender27243122731
getState18816024125197241
initialActions63185618
loadScripts959722175232513181752
setupStore1191411214
numNetworkReqs411192766196670766
WebpackStandard HomeuiStartup8597441109728721035
load64458994073650852
domContentLoaded63658392971644844
domInteractive16125181438
firstPaint20457932220179816
backgroundConnect24115892548
firstReactRender28185883236
getState1262341418
initialActions3016247
loadScripts63358191969642833
setupStore1052731213
numNetworkReqs96338832
WebpackPower User HomeuiStartup17151307251839522672518
load73061011991648371199
domContentLoaded69458610451367781045
domInteractive21144493344
firstPaint4017910503447821050
backgroundConnect13719486152307486
firstReactRender26223832738
getState15711720917161209
initialActions14187261087
loadScripts69058410311327701031
setupStore2761153126115
numNetworkReqs416223805184600805
FirefoxBrowserifyStandard HomeuiStartup1424121917428714741577
load1220106114027512691356
domContentLoaded1220106114027512681355
domInteractive1203427644135226
firstPaint------
backgroundConnect4124127164972
firstReactRender24205042528
getState84558816
initialActions4267736
loadScripts1195104513747112371333
setupStore1174451116
numNetworkReqs96357728
BrowserifyPower User HomeuiStartup28322256375745430953757
load14361255170911115051709
domContentLoaded14361255170811115051708
domInteractive16810726043211260
firstPaint------
backgroundConnect22239558141317558
firstReactRender463084135084
getState1419519827165198
initialActions16283211983
loadScripts13711227164911514561649
setupStore44111824560182
numNetworkReqs25712641981318419
WebpackStandard HomeuiStartup15601314201912216041853
load13421154181110513981529
domContentLoaded13421154181110513971528
domInteractive1072942371108317
firstPaint------
backgroundConnect4424124195081
firstReactRender292273112968
getState8412312713
initialActions41677310
loadScripts13161138178410313721499
setupStore12767101136
numNetworkReqs106347731
WebpackPower User HomeuiStartup28642379397850933903978
load16521372221826917682218
domContentLoaded16521371221726917672217
domInteractive1457433267184332
firstPaint------
backgroundConnect25556917292494917
firstReactRender35305374153
getState1279719433162194
initialActions12255141255
loadScripts15681326198420516561984
setupStore47161573674157
numNetworkReqs357192585132507585
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 68 Bytes (0%)
  • ui: 0 Bytes (0%)
  • common: 10 Bytes (0%)

@metamaskbot
Copy link
Collaborator

📊 Page Load Benchmark Results

Current Commit: 4b6c51f | Date: 10/31/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.01s (±42ms) 🟡 | historical mean value: 1.04s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 703ms (±38ms) 🟢 | historical mean value: 724ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 74ms (±13ms) 🟢 | historical mean value: 76ms ⬇️ (historical data)
📈 Detailed Results
Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.01s 42ms 974ms 1.31s 1.04s 1.31s
domContentLoaded 703ms 38ms 671ms 978ms 733ms 978ms
firstPaint 74ms 13ms 56ms 196ms 84ms 196ms
firstContentfulPaint 74ms 13ms 56ms 196ms 84ms 196ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms

Results generated automatically by MetaMask CI

@metamaskbot
Copy link
Collaborator

Builds ready [4b6c51f]
UI Startup Metrics (1156 ± 76 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup115698913097612121281
load98285011486910281102
domContentLoaded97584411436810181095
domInteractive201398141750
firstPaint67069112438010051078
backgroundConnect1801682026184191
firstReactRender29165883443
getState20785112142
initialActions80589928
loadScripts80167997167846924
setupStore1064041019
numNetworkReqs96337631
BrowserifyPower User HomeuiStartup22351749418872930684188
load1158940177632816651776
domContentLoaded1150933175632516531756
domInteractive261462144062
firstPaint70990176552310051765
backgroundConnect24921935636275356
firstReactRender26243222832
getState17716225924182259
initialActions112108255108
loadScripts911718147729513591477
setupStore1091521115
numNetworkReqs341160727208685727
WebpackStandard HomeuiStartup90570912591029481116
load648555104172664787
domContentLoaded639548103070658779
domInteractive17125981738
firstPaint24253863231232776
backgroundConnect291366103450
firstReactRender311765103745
getState1462951722
initialActions4018358
loadScripts636546102169655769
setupStore1263041518
numNetworkReqs96337830
WebpackPower User HomeuiStartup16971307247939722752479
load76964212381989901238
domContentLoaded72862610911539121091
domInteractive19134582245
firstPaint4667010943699691094
backgroundConnect12919475157342475
firstReactRender26244042640
getState15610420220157202
initialActions814914849
loadScripts72362310801509001080
setupStore17644133044
numNetworkReqs333164706166506706
FirefoxBrowserifyStandard HomeuiStartup14631269188310315461667
load1244109214618113131388
domContentLoaded1244109114618113131386
domInteractive1133627536129193
firstPaint------
backgroundConnect4525126185488
firstReactRender26215772647
getState74767712
initialActions621842047
loadScripts1217107414307812741355
setupStore1175051215
numNetworkReqs96357731
BrowserifyPower User HomeuiStartup28412193397860835543978
load14401174176516716161765
domContentLoaded14391174176516716161765
domInteractive1669228765245287
firstPaint------
backgroundConnect22431707221411707
firstReactRender39305984659
getState14011419727164197
initialActions2612205425220
loadScripts13841156171715815571717
setupStore3871423763142
numNetworkReqs263155593127344593
WebpackStandard HomeuiStartup1614147120759216651783
load1391124616987914471537
domContentLoaded1391124516977914471537
domInteractive1102936647117218
firstPaint------
backgroundConnect4727121175583
firstReactRender3123104143071
getState946571017
initialActions4168739
loadScripts1363122716267714151516
setupStore1172421215
numNetworkReqs96326726
WebpackPower User HomeuiStartup28212287381245933443812
load15901363197320117721973
domContentLoaded15901362197320117711973
domInteractive1237027250155272
firstPaint------
backgroundConnect22650845238233845
firstReactRender423077114677
getState1359220132146201
initialActions912881128
loadScripts15271283183118817241831
setupStore371176255676
numNetworkReqs276154555132345555
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 39 Bytes (0%)
  • ui: 59 Bytes (0%)
  • common: 875 Bytes (0.01%)

@gauthierpetetin gauthierpetetin marked this pull request as draft October 31, 2025 10:47
@gauthierpetetin gauthierpetetin changed the title fix(premature close): gracefully end stream muxes on transport termination to prevent pipeline errors fix(premature close): gracefully end extension stream muxes to prevent "Premature close" errors Oct 31, 2025
@metamaskbot
Copy link
Collaborator

Builds ready [e72ec5e]
UI Startup Metrics (1257 ± 78 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup1257109414757813171386
load107394712947211281189
domContentLoaded106692312887311211185
domInteractive201471121852
firstPaint65181130244010921174
backgroundConnect23221535015235250
firstReactRender28176783342
getState2296392539
initialActions61406720
loadScripts842694106374897964
setupStore1162741221
numNetworkReqs96327630
BrowserifyPower User HomeuiStartup22831856367165332003671
load1157965171528515731715
domContentLoaded1150960170828315651708
domInteractive281657154257
firstPaint535115171645110101716
backgroundConnect26522340752283407
firstReactRender26233232932
getState19515945671181456
initialActions815913659
loadScripts904735138725012271387
setupStore1191721217
numNetworkReqs329140695206660695
WebpackStandard HomeuiStartup791680104865815920
load59053786463598720
domContentLoaded58252985763591713
domInteractive14113851330
firstPaint20055711187167652
backgroundConnect24124482943
firstReactRender25165583132
getState1052231316
initialActions209236
loadScripts57952785062589711
setupStore941431113
numNetworkReqs106348832
WebpackPower User HomeuiStartup17361316250335822362503
load732623979139950979
domContentLoaded695608945108814945
domInteractive19134292742
firstPaint49396985323820985
backgroundConnect12517443155254443
firstReactRender27223953139
getState16114719414171194
initialActions14160203760
loadScripts691606934104802934
setupStore15641133441
numNetworkReqs323187583146552583
FirefoxBrowserifyStandard HomeuiStartup1463131418207714971605
load1250111514075912831371
domContentLoaded1249111514075912831371
domInteractive1093724834120191
firstPaint------
backgroundConnect4326192204761
firstReactRender26215972548
getState10427527713
initialActions4121246
loadScripts1223109013805812541344
setupStore1163331214
numNetworkReqs96337731
BrowserifyPower User HomeuiStartup26872228399450829983994
load13901208171314715291713
domContentLoaded13891208171314715291713
domInteractive1659333088280330
firstPaint------
backgroundConnect16734681198243681
firstReactRender38315164451
getState1468330857175308
initialActions1911253215125
loadScripts13461185157712514941577
setupStore4473297642329
numNetworkReqs23114944894274448
WebpackStandard HomeuiStartup16301463222215416342006
load13921235171910914171685
domContentLoaded13911235171810914171685
domInteractive1103440069109327
firstPaint------
backgroundConnect46241572249103
firstReactRender332174143073
getState84838817
initialActions52769411
loadScripts13631215169410213891645
setupStore1367691421
numNetworkReqs106348732
WebpackPower User HomeuiStartup27132287345733629013457
load15511305192917517101929
domContentLoaded15501305192917517101929
domInteractive1306721041174210
firstPaint------
backgroundConnect15830568158323568
firstReactRender44305375053
getState1427722940184229
initialActions11264151364
loadScripts15071272187416416141874
setupStore31886225586
numNetworkReqs258154593114310593
📊 Page Load Benchmark Results

Current Commit: e72ec5e | Date: 10/31/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.03s (±38ms) 🟡 | historical mean value: 1.04s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 721ms (±36ms) 🟢 | historical mean value: 723ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 76ms (±12ms) 🟢 | historical mean value: 77ms ⬇️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.03s 38ms 1.01s 1.32s 1.07s 1.32s
domContentLoaded 721ms 36ms 703ms 988ms 749ms 988ms
firstPaint 76ms 12ms 60ms 184ms 84ms 184ms
firstContentfulPaint 76ms 12ms 60ms 184ms 84ms 184ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 142 Bytes (0%)
  • ui: 5.61 KiB (0.08%)
  • common: 2.87 KiB (0.03%)

@gauthierpetetin gauthierpetetin marked this pull request as ready for review October 31, 2025 20:29
@github-project-automation github-project-automation bot moved this to Needs dev review in PR review queue Oct 31, 2025
@DDDDDanica
Copy link
Contributor

LGTM !!

@github-project-automation github-project-automation bot moved this from Needs dev review to Review finalised - Ready to be merged in PR review queue Nov 7, 2025
@gauthierpetetin gauthierpetetin added this pull request to the merge queue Nov 7, 2025
Merged via the queue into main with commit f638960 Nov 7, 2025
201 checks passed
@gauthierpetetin gauthierpetetin deleted the premature-close-error branch November 7, 2025 09:59
@github-project-automation github-project-automation bot moved this from Review finalised - Ready to be merged to Merged, Closed or Archived in PR review queue Nov 7, 2025
@github-actions github-actions bot locked and limited conversation to collaborators Nov 7, 2025
@metamaskbot metamaskbot added the release-13.10.0 Issue or pull request that will be included in release 13.10.0 label Nov 7, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release-13.10.0 Issue or pull request that will be included in release 13.10.0 size-L team-extension-platform Extension Platform team

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

Error: Premature close Identify the root cause of the "Premature close" error [Bug]: Error: premature close

5 participants