コンテンツへスキップ

Playwrightの生エラー(Call log: …)をそのままユーザーに見せない — 例外メッセージの翻訳設計

Playwrightの生エラー(Call log: ...)をそのままユーザーに見せない — 例外メッセージの翻訳設計

Playwright で何かが失敗すると、例外メッセージには Call log: から始まる長いデバッグ情報が付いてくる。デバッグには有用だが、保守ツールの利用者にそのまま表示すると、何が起きたのか分からない。

補足: Playwright の例外オブジェクトを str() で文字列化すると、実際に起きたエラーの説明に加えて、内部的にどんな処理を試みたかのログが何行も連なって出てくることが多い。

問題の構造

Playwright がタイムアウトすると、例外メッセージはこのような形になる。

Timeout 30000ms exceeded.
Call log:
  - navigating to "https://example.com/wp-admin/", waiting until "load"
  - navigation interrupted by another navigation to "https://example.com/wp-login.php"
  ...

1行目だけなら意味が伝わるが、Call log: 以降は内部の処理ステップの記録であり、利用者には不要な情報だ。これをそのまま画面に出すと、「何が壊れたか」より「Playwright が何をしようとしていたか」が前面に出てしまい、利用者は次に何をすべきか判断できない。

対処 — エラーの種類で分岐し、定型文に変換する

例外メッセージの内容を見て、よくあるエラーパターンに当てはまればその種類専用の短い説明文を返す。当てはまらなければ、最初の1行だけを採用し、それも長すぎる場合は切り詰める。

def _friendly_error(e) -> str:
    msg = str(e)
    if 'Timeout' in type(e).__name__ or 'timeout' in msg.lower():
        return "サイトへの接続がタイムアウトしました(30秒以内に応答なし)"
    if 'net::ERR_NAME_NOT_RESOLVED' in msg or 'Name or service not known' in msg:
        return "ドメインを解決できませんでした(DNS エラー)"
    if 'net::ERR_CONNECTION_REFUSED' in msg:
        return "サーバーへの接続が拒否されました"
    if 'SSL' in msg or 'certificate' in msg.lower():
        return "SSL証明書のエラーが発生しました"
    if 'Login' in msg or 'ログイン' in msg:
        return "WordPress管理画面へのログインに失敗しました"
    # それ以外は最初の1行だけ返す(Call log 以降を切り捨て)
    first_line = msg.splitlines()[0] if msg else "不明なエラー"
    return first_line[:120] if len(first_line) > 120 else first_line

判定の順序にも意味がある。Timeout は例外の型名(TimeoutError)からも判定できるが、メッセージ文字列に timeout という単語が含まれるケースもあるため両方を見る。DNS エラー・接続拒否・SSL証明書エラーは、それぞれ Playwright(Chromium)が出すエラーコード文字列(net::ERR_...)が決まっているので、文字列の部分一致で判定できる。

なぜ「最初の1行だけ」が安全な切り捨てラインになるか

Playwright の例外メッセージは、基本的に「1行目に実際のエラー内容、2行目以降に Call log: のデバッグ情報」という構造になっている。すべてのエラーパターンを事前に網羅することはできないので、想定外のエラーに対しては「とりあえず1行目を返す」というフォールバックを用意しておく。これにより、未知のエラーでも Call log: 以下のノイズだけは確実に除外できる。

設計のポイント

これは単なる文字列の整形ではなく、「開発者が知りたい情報」と「利用者が知りたい情報」は別物だという前提をコードに落とし込んだものだ。生の例外はログには残し、画面には出さない。利用者には「次にどうすればいいか」が分かる短い日本語だけを返す、という役割分担をエラーハンドリングの層で明確に分けている。

まとめ

観点 内容
問題 Playwright の生エラーには Call log: 以降の内部処理ログが付き、利用者には不要な情報になる
対処 エラーの種類ごとに専用の短い説明文を用意し、当てはまらなければ最初の1行だけにフォールバック
判定方法 例外の型名とメッセージ文字列の両方を見る。Chromium のエラーコード(net::ERR_...)は部分一致で判定できる
設計の軸 「開発者向けの生情報」と「利用者向けの短い説明」を明確に分離する

一括選択チェックボックスが反映されない罠update-core.php のバージョン番号誤検出とは少し違う角度の話だが、根底にあるのは同じく「Playwright が返してくる生の情報を、そのまま信用・そのまま表示しない」という姿勢だ。何かを自動化するツールを書くなら、失敗したときに何を見せるかも設計の一部だと思う。


続編: ブラウザ更新モードで除外プラグインが更新されてしまう罠 — Playwright 経路への設定反映と残余チェック誤警告の修正