From TargetClosedError to a Native Edge Crash

Summary

  • Playwright reported TargetClosedError while handling a download.
  • Microsoft Edge had already terminated before download.save_as() failed.
  • A new profile completed five downloads during its first browser process, but the failure appeared after reusing that profile across subsequent Edge processes.
  • The initial application exception was therefore treated as a symptom. The investigation moved downward through Playwright, CDP transport, and the Edge process itself.

Initial signal

The investigation started with two log entries:

browser_disconnected reason=unexpected
Download.save_as: Target page, context or browser has been closed

Taken alone, these messages suggest a lifecycle problem in the application: the page may have been closed too early, or save_as() may have been called at the wrong time.

Process-level logging changed that interpretation. Edge exited before Playwright attempted to finish the save operation. The sequence was:

Edge process terminates
CDP connection closes
Browser, Context, and Page become unavailable
download.save_as() reports TargetClosedError

The Playwright exception was accurate, but it did not explain why the browser disappeared.

Components involved

Component Role in the test
Playwright Starts and controls the browser in the original reproduction
Microsoft Edge Executes the page and download operations
CDP Carries browser automation commands
User-data directory Persists profile state between Edge processes
Pipe or port Provides the CDP transport path
Crashpad Records process crash information

Playwright’s launch_persistent_context() starts a browser against a specified user-data directory. This is useful when an automated workflow needs to retain cookies or local storage between runs.

That convenience also joins several layers into one API call: Playwright launches Edge, communicates through CDP, Edge performs the network request, and the operating system writes the downloaded file. A generic error at the API boundary can originate in any of those layers.

First reproduction pattern

The initial results appeared to implicate an existing profile:

Condition Observed result
Previously used profile Repeated abnormal termination during the download workflow
New profile, five downloads in one Edge process 5 / 5 successful

The new profile result did not hold after restarting Edge:

New profile, first Edge process       -> five downloads succeed
Same profile, later Edge process      -> crash on the second or third launch

Multiple independently created profiles showed the same pattern. The meaningful condition was not simply whether a profile was old or new; it was whether the same profile state was reused by another Edge process.

Working hypotheses

At this stage, the plausible explanations included:

  • corruption limited to the original profile;
  • behavior specific to headless mode;
  • an error caused by download.save_as();
  • Playwright-specific browser arguments or CDP command ordering;
  • a native failure within Edge.

The next tests changed one condition at a time. Successes and failures were recorded with the same environment, input file, and shutdown sequence wherever possible.

Test environment

The results in this series were observed on September 3, 2026.

Item Version
Operating system Windows 11 Home x64, build 26200
Microsoft Edge Stable 152.0.4191.53, x64
Playwright for Python 1.62.0
Playwright-bundled Chromium 151.0.7922.34
Python / Node.js 3.12.14 / 24.18.1

These observations do not establish that every Edge 152 environment is affected. The responsible source component and the regression range were not identified at this point.

Next test

The next note tests the most visible alternatives: a newly created profile, headed versus headless operation, and download handling with and without save_as().