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?

【浅層編】Edgeプロファイルのアビスに潜ったら、新品も次の起動でクラッシュした件 — headlessとsave_asの冤罪を晴らす

0
Last updated at Posted at 2026-09-03

CDPのアビス — 全4編

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

現在地:浅層編

Executive Summary — 地上への帰還報告

  • 新規プロファイルは、最初のEdge起動中なら5件のダウンロードに成功した。しかし、そのプロファイルを再利用してEdgeを起動すると、2回目または3回目の起動中にクラッシュした。
  • 画面を表示するheaded実行と、表示しないheadless実行の両方で再現した。headless固有の問題ではなかった。
  • Playwrightの Download.save_as() を使わない経路でも再現した。save_as() はクラッシュ原因ではなく、Edge終了後に異常を観測した場所だった。
  • 浅層で目立つ容疑者を外しても異変は残ったため、次はPlaywrightそのものを置いて、CDPと直接通信する深層へ降りる必要があった。

この層の呪い:新品のプロファイルが最初の探索に成功し、問題が消えたように見せる。
この層の祝福:条件を一つずつ外すたび、無実の容疑者を地上へ帰せる。
深層碑文:「一度の無事な帰還は、安全の証明ではない。次の降下が地形を変えることもある。」

現在深度:浅層から中層

地上編では、TargetClosedError が最深部の原因を説明していないことを確認した。

この編で調べるのは、地上から見えやすい三つの容疑者である。

浅層1  古いプロファイルの破損
浅層2  headlessという特殊な実行方法
中層3  Download.save_as()という保存API

調査の基本ルールは単純だ。

一度に一つの装備だけを外し、それ以外の条件を変えない。

複数の条件を同時に変えると、成功しても失敗しても理由が分からなくなる。

第一層:古いプロファイルだけが呪われているのか

最初にクラッシュしたのは、以前から使っていたEdgeプロファイルだった。

プロファイルにはCookie、キャッシュ、設定、ログイン状態など、多くのデータが蓄積する。古いプロファイルだけが壊れているという仮説は自然である。

そこで、既存の個人プロファイルから完全に離れ、テスト専用の空フォルダからEdgeに新規プロファイルを作らせた。

その結果、最初の起動では5つのリンクから5件すべてをダウンロードできた。

新規プロファイル
└─ Edge起動1回目
   ├─ download 1: 成功
   ├─ download 2: 成功
   ├─ download 3: 成功
   ├─ download 4: 成功
   └─ download 5: 成功

ここで探索を終えれば、「新しいプロファイルへ交換すれば直る」と判断してしまう。

しかし、同じプロファイルを持ち帰り、Edgeを正常終了し、もう一度使うと異変が現れた。

同じ新規プロファイル
├─ Edge起動1回目: 成功
└─ Edge起動2回目または3回目: ダウンロード中にクラッシュ

複数の独立した新規プロファイルで同じ傾向を確認した。したがって、元の個人プロファイルだけの破損では説明できない。

重要なのは「古いか新しいか」ではなく、一度使ったプロファイルを次のEdgeプロセスへ引き継ぐことだった。

第二層:暗闇で潜るheadlessが悪いのか

ブラウザ自動化には二つの見た目がある。

モード 説明
headed 通常のブラウザ画面を表示する
headless 画面を表示せず、裏側で実行する

画面のないheadlessは特殊に見えるため、トラブル時に疑われやすい。

しかし、結果は両方とも同じだった。

headless: 起動1回目は成功、起動2回目に切断
headed:   起動1回目は成功、起動2回目に切断

さらに、後で回収した両モードのクラッシュダンプは、msedge.dll 内の同じ命令位置を示した。

暗闇で潜ったから落ちたのではない。画面を表示していても、同じ深度で同じ事故が起きていた。

第三層:save_as() が足場を壊したのか

地上へ返ってきた例外には、次の名前が刻まれていた。

Download.save_as: Target page, context or browser has been closed

もっとも目立つのは save_as() である。そこで保存方法を変えた。

検証 結果
Download.save_as() で保存 Edgeが終了し、TargetClosedError
download.path() で一時ファイルを参照 同じクラッシュを確認
PlaywrightのDownload APIを使わないraw CDP 同じEdgeネイティブクラッシュを確認

時系列を並べると理解しやすい。

1. Edge内部でネイティブクラッシュ
2. Edgeプロセスが終了
3. CDP接続が失われる
4. PlaywrightのBrowser / Context / Pageが閉じた状態になる
5. save_as() がTargetClosedErrorを返す

save_as() は最後に悲鳴を上げた。しかし、足場を壊した本人ではなかった。

ダウンロード方式を変えても残るのか

Playwright 1.62.0が使うダウンロード許可方式に近い allowAndName と、より単純な allow も比較した。

pipe + allow        : 再現
pipe + allowAndName : 再現
port + allowAndName : 連続成功

ファイル名の扱いだけでは、pipe経路のクラッシュを説明できなかった。

起動引数という装備を外す

PlaywrightはChromium系ブラウザを安定して操作するため、複数の起動引数を自動で付ける。

そこで、次の候補を段階的に外した。

  • Playwrightの長い --disable-features=... 指定
  • DestroyProfileOnBrowserClose に関係する差
  • Edge固有の更新・互換性関連スイッチ
  • そのほか再現に不要なPlaywright既定引数

それでも、最小化したpipe起動でクラッシュは残った。試行によって発生が2回目から3回目へ動くことはあったが、消えなかった。

これは「すべての起動引数が無関係」と証明するものではない。ただし、特定の分かりやすい一引数を外せば直る、という単純な形ではなかった。

浅層の探索結果

ここまでの仮説を整理する。

仮説 判定 根拠
元のプロファイルだけが破損していた 棄却 新規プロファイルでも再利用後に再現
headlessだけの問題 棄却 headedでも再現し、ダンプ位置も一致
save_as() が必要原因 棄却 PlaywrightのDownload APIなしでも再現
allowAndName だけの問題 棄却 allow でも再現
一つの既定起動引数だけが原因 支持されず 最小化したpipe起動でも再現

浅層で目立っていた容疑者は帰った。

残った大きな問いは一つである。

Playwrightを完全に外しても、同じEdgeクラッシュへ辿り着けるのか。

次の層へ:案内役を置いていく

ここまではPlaywrightという案内役と一緒に降りてきた。

次の深界編では、Playwright、Puppeteer、Selenium、外部npmパッケージをすべて置いていく。Node.jsの標準機能だけでEdgeへCDPメッセージを送り、同じ5 MiBファイルをダウンロードさせる。

そこで現れるのが、ほぼ同じ縦穴に見える pipeport の分岐である。


深度案内

  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?