Don't show users a raw Playwright error — translating exceptions into friendly messages

작성자

카테고리:

← 피드로
DEV Community · Susumu Takahashi · 2026-08-05 개발(SW)
Cover image for Don't show users a raw Playwright error — translating exceptions into friendly messages

Susumu Takahashi

When something fails in Playwright, the exception message comes with a long block of debug information starting with Call log:. That’s useful while debugging, but showing it as-is to someone using a maintenance tool tells them nothing about what actually went wrong.

Note: Stringifying a Playwright exception object usually produces not just the description of what failed, but several lines logging what the library internally tried to do along the way.

The shape of the problem

When Playwright times out, the exception message looks something like this:

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"
  ...

Enter fullscreen mode Exit fullscreen mode

The first line alone conveys something meaningful. Everything after Call log: is an internal trace of processing steps — information the end user doesn’t need. Showing this raw puts “what Playwright was attempting” front and center instead of “what actually broke,” leaving the user with no clear next step.

The fix — branch by error type, return a fixed phrase

Look at the exception message, match it against a list of common error patterns, and return a short type-specific explanation for whichever one matches. If nothing matches, fall back to just the first line, truncated if it’s too long.

def _friendly_error(e) -> str:
    msg = str(e)
    if 'Timeout' in type(e).__name__ or 'timeout' in msg.lower():
        return "Connection to the site timed out (no response within 30 seconds)"
    if 'net::ERR_NAME_NOT_RESOLVED' in msg or 'Name or service not known' in msg:
        return "Could not resolve the domain (DNS error)"
    if 'net::ERR_CONNECTION_REFUSED' in msg:
        return "Connection to the server was refused"
    if 'SSL' in msg or 'certificate' in msg.lower():
        return "An SSL certificate error occurred"
    if 'Login' in msg or 'login' in msg.lower():
        return "Failed to log in to the WordPress admin screen"
    # Fall back to the first line only (everything after Call log: gets dropped)
    first_line = msg.splitlines()[0] if msg else "Unknown error"
    return first_line[:120] if len(first_line) > 120 else first_line

Enter fullscreen mode Exit fullscreen mode

The order of these checks matters. A timeout can be detected from the exception’s type name (TimeoutError), but the word “timeout” can also show up inside the message string itself, so the code checks both. DNS errors, connection refusals, and SSL certificate errors each correspond to a fixed Chromium error code string (net::ERR_...), which is reliable enough to match with a simple substring check.

Why “just the first line” is a safe fallback

Playwright’s exception messages follow a consistent shape: the first line is the actual error, everything from Call log: onward is debug trace. There’s no way to enumerate every possible error pattern ahead of time, so the fallback for anything unrecognized is “return the first line.” That alone reliably strips out the Call log: noise even for errors the code has never seen before.

What this design gets right

This isn’t just string formatting — it encodes the premise that what a developer wants to know and what a user wants to know are two different things. The raw exception still gets logged for debugging; what reaches the screen is a short message telling the user what to do next. The error-handling layer keeps those two responsibilities cleanly separated.

Summary

Aspect Detail Problem Raw Playwright errors come with Call log: internal trace noise that users don’t need Fix Map common error types to short fixed phrases; fall back to the first line for anything unrecognized Detection Check both the exception’s type name and substrings in the message; Chromium error codes (net::ERR_...) match reliably Design principle Keep “raw info for developers” and “short explanation for users” as clearly separate concerns

This is a slightly different angle from the select-all checkbox trap or the version-scraping false positive in update-core.php, but the underlying stance is the same: don’t trust, and don’t display, whatever raw information Playwright hands back without thinking about it first. If you’re writing a tool that automates something, deciding what to show when it fails is part of the design, not an afterthought.

Follow-up: The excluded-plugin setting that Playwright ignored — fixing browser-mode updates and false residual warnings

원문에서 계속 ↗

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다