d2lang/d2 · error

failed to close Playwright browser: %w

Error message

failed to close Playwright browser: %w

What it means

RestartBrowser tears down the current Playwright browser before starting a new one. If pw.Browser.Close() returns an error, the restart aborts with this wrapped error instead of proceeding to start a replacement browser. This usually indicates the browser process is already dead or wedged.

Source

Thrown at lib/png/png.go:34

	"github.com/mxschmitt/playwright-go"

	"github.com/d2lang/d2/lib/compression"
	"github.com/d2lang/d2/lib/env"
	"github.com/d2lang/d2/lib/version"
)

// ConvertSVG scales the image by 2x
const SCALE = 2.

type Playwright struct {
	PW      *playwright.Playwright
	Browser playwright.Browser
	Page    playwright.Page
}

func (pw *Playwright) RestartBrowser() (Playwright, error) {
	if err := pw.Browser.Close(); err != nil {
		return Playwright{}, fmt.Errorf("failed to close Playwright browser: %w", err)
	}
	return startPlaywright(pw.PW)
}

func (pw *Playwright) Cleanup() error {
	if err := pw.Browser.Close(); err != nil {
		return fmt.Errorf("failed to close Playwright browser: %w", err)
	}
	if err := pw.PW.Stop(); err != nil {
		return fmt.Errorf("failed to stop Playwright: %w", err)
	}
	return nil
}

func startPlaywright(pw *playwright.Playwright) (Playwright, error) {
	// Optimizations for a very tightly scoped Playwright instance
	browser, err := pw.Chromium.Launch(playwright.BrowserTypeLaunchOptions{
		Args: []string{

View on GitHub (pinned to 0d69dca6f5)

Solutions

  1. Check whether the browser process crashed (logs/OOM killer) and address the resource cause before restarting
  2. If the browser is already closed/dead, treat Close's error as non-fatal and proceed with startPlaywright directly
  3. Ensure RestartBrowser isn't called concurrently with Cleanup or itself; serialize lifecycle calls with a mutex
  4. Verify Playwright driver and browser versions are compatible; reinstall browsers if the install is corrupted

Example fix

// before
if err := pw.Browser.Close(); err != nil {
	return Playwright{}, fmt.Errorf("failed to close Playwright browser: %w", err)
}
// after
if err := pw.Browser.Close(); err != nil {
	// browser likely already dead; continue with restart
	log.Printf("browser close failed (ignoring): %v", err)
}
Defensive patterns

Strategy: try-catch

Try / catch

if _, err := pw.RestartBrowser(); err != nil {
	if strings.Contains(err.Error(), "failed to close Playwright browser") {
		// browser already dead — call startPlaywright directly instead of failing
	}
}

Prevention

When it happens

Trigger: Browser.Close() fails during RestartBrowser — typically the Chromium process already crashed or was killed (OOM, SIGKILL), the driver lost the connection, or Close is called on an already-closed browser.

Common situations: Long-running bundler workers where Chromium crashed under memory pressure; concurrent Close calls from multiple goroutines; calling RestartBrowser after Cleanup already stopped everything.

Related errors


AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31). Data as JSON: /api/errors/e1198b9ad0cff6b7. Report an issue: GitHub.