0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【地上編】PlaywrightのTargetClosedErrorを追っていたら、CDPのアビスを降りてEdgeのネイティブクラッシュに辿り着いた件

0
Last updated at Posted at 2026-09-03

CDPのアビス — 全4編

地上編
浅層編
深界編
最深部編

現在地:地上編

Executive Summary — 地上への帰還報告

  • 地上で観測したのは、Playwrightの TargetClosedErrorDownload.save_as() の失敗だった。
  • しかし、実際にはその前にMicrosoft Edge自体がネイティブクラッシュしていた。画面に出たエラーは原因ではなく、深層で起きた事故が上層へ伝わった結果だった。
  • 新しいプロファイルで5件を続けてダウンロードするだけなら5/5成功した。異変は、同じプロファイルでEdgeを終了・再起動した後に現れた。
  • 本連載では、地上のアプリコードからPlaywright、CDP、通信経路、Edge内部へと一層ずつ降り、最後に安全な帰還路となる回避策を探す。

この層の呪い:深層の原因が、地上へ戻るまでに一般的な TargetClosedError へ圧縮される。
この層の祝福:エラーの発生順を逆にたどれば、降りるべき層が見えてくる。
深層碑文:「地上で見えるエラーは、深層で起きた事故が落とした影にすぎない。」

深度0:地上で鳴った警報

調査の出発点は、ログに残った2行だった。

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

日本語にすると、次のような意味になる。

  • ブラウザとの接続が予期せず切れた
  • 保存しようとしたが、操作対象はすでに閉じていた

このログを地上から眺めると、save_as() の使い方かPlaywrightのライフサイクル管理が怪しく見える。

だが、警報器が鳴った場所と、事故が起きた場所は同じとは限らない。

地上       業務アプリに見えた TargetClosedError
  │
浅層       PlaywrightのPage / Context / Download
  │
中層       プロファイル再利用とブラウザ再起動
  │
深層       CDPとpipe / portの通信経路
  │
最深部     Edgeプロセスとmsedge.dllのネイティブ処理

今回のエラーは、最深部で起きた事故が上の層へ伝わる途中で、情報を失いながら TargetClosedError へ姿を変えたものだった。

このアビスの登場人物

専門用語を、探索装備として先に整理しておく。

用語 役割 探索上のたとえ
Playwright ブラウザをプログラムから操作する道具 地上から指示を出す操縦者
Microsoft Edge ページを開き、実際にダウンロードするブラウザ 深層で動く大型機械
CDP Chromium系ブラウザへ命令を送る共通プロトコル 層をまたいで届く共通言語
プロファイル Cookie、設定、ログイン状態などを保存する場所 探索のたびに持ち帰る荷物
pipe / port CDPメッセージを運ぶ二つの経路 深層へ続く別々の縦穴
Crashpadダンプ 異常終了時に残される記録 深層から回収した記録石

Playwrightの launch_persistent_context() は、指定したプロファイルを使ってブラウザを起動する。Cookieやローカルストレージを維持できるため、ログイン状態を保つ自動処理で便利なAPIである。

一方、便利な一つのAPIの下には、複数の層が隠れている。地上からは一行に見えても、内部ではPlaywrightがEdgeを起動し、CDPで命令し、EdgeがOS上でファイルを書き込む。

上昇負荷:深層の情報は地上へ戻るほど失われる

ここでいう「上昇負荷」は、深い層の異常が上位APIへ返る過程で、原因情報が一般的なエラーへ圧縮されることを指す。

最深部: msedge.dllで無効なメモリ読み取り
    ↓
深層: Edgeプロセスが終了し、CDP接続が切断
    ↓
浅層: Browser / Context / Pageが閉じた状態になる
    ↓
地上: Download.save_as() がTargetClosedErrorを返す

地上のエラーは嘘ではない。確かに対象は閉じている。

ただし、「なぜ閉じたのか」という最も重要な情報は、そこには残っていない。地上のログだけを直しても、深層の事故は止められない。

最初に見つけた不自然な地形

当初、プロファイルによって結果が違って見えた。

条件 結果
以前から使っていたプロファイル 同じダウンロード処理で繰り返し異常終了
新しく作ったプロファイルで、1回のEdge起動中に5件ダウンロード 5/5成功

ここだけなら、「古いプロファイルが壊れていた」で話を終えられる。

しかし、新しいプロファイルを持ち帰り、Edgeを終了し、同じプロファイルで再び起動すると状況が変わった。

新規プロファイルの初回起動        → 5件成功
同じプロファイルを再利用した起動  → 2回目または3回目にクラッシュ

異変を起こしたのは5件という数ではなかった。「一度使ったプロファイルを持って、もう一度潜ること」が重要な条件だった。

地上で立てた仮説

この時点で、複数の容疑者がいる。

  • 古いプロファイルだけが壊れているのではないか
  • 画面を表示しないheadless実行が不安定なのではないか
  • Download.save_as() がEdgeを閉じているのではないか
  • Playwrightの起動引数やCDP命令順に問題があるのではないか
  • Edge自体がクラッシュしているのではないか

地上から推測を重ねても答えは出ない。次に必要なのは、装備を一つずつ外し、条件を一つずつ変えることだった。

検証環境

本連載の回数と結果は、2026年9月3日に次の環境で観測した値である。

項目 バージョン
OS Windows 11 Home x64、build 26200
Microsoft Edge Stable 152.0.4191.53、x64
Playwright for Python 1.62.0
Playwright同梱Chromium 151.0.7922.34
Python / Node.js 3.12.14 / 24.18.1

すべてのEdge環境で発生すると結論したわけではない。原因コンポーネントと回帰範囲も、まだ確定していない。

次の層へ

次編では浅層から中層へ降りる。

古いプロファイル、headless、save_as() という分かりやすい容疑者を、一人ずつ実験で帰していく。そこで残るのは、「同じプロファイルを持ってEdgeを再起動する」という地形そのものだった。


深度案内

  1. 地上編:TargetClosedError は最深部の事故を説明しない(本記事)
  2. 浅層編:新品のプロファイルも、再利用すると様子が変わる
  3. 深界編:Playwrightを置いてraw CDPでpipe / port分岐へ降りる
  4. 最深部編:Crashpadの記録石を読み、帰還路を選ぶ
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?