d2lang/d2 · warning
failed to stop Playwright: %w
Error message
failed to stop Playwright: %w
What it means
Cleanup, after successfully closing the browser, stops the Playwright driver process with pw.PW.Stop(). If that fails it returns this wrapped error. The driver (node process managing browsers) could not be terminated, potentially leaving orphaned node/Chromium processes.
Source
Thrown at lib/png/png.go:44
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{
"--no-sandbox", // Removes security overhead
"--disable-dev-shm-usage", // Prevents /dev/shm issues
"--disable-background-timer-throttling", // Prevents CPU throttling
"--disable-backgrounding-occluded-windows", // Keeps rendering active
"--disable-features=TranslateUI", // Reduces feature overhead
"--disable-ipc-flooding-protection", // Removes IPC limits
},
})
if err != nil {
return Playwright{}, fmt.Errorf("failed to launch Chromium: %w", err)View on GitHub (pinned to 0d69dca6f5)
Solutions
- Check for orphaned node/chromium processes after the error and kill them manually if needed
- Make Cleanup idempotent and single-run (sync.Once) to avoid racing Stop against itself
- Log and continue: Stop failure at process exit is rarely fatal, so don't mask the original operation's result with it
- Upgrade playwright-go to the latest version — driver lifecycle bugs are fixed regularly
Example fix
// before
if err := pw.PW.Stop(); err != nil {
return fmt.Errorf("failed to stop Playwright: %w", err)
}
// after
if err := pw.PW.Stop(); err != nil {
log.Printf("playwright stop failed (driver may have already exited): %v", err)
} Defensive patterns
Strategy: try-catch
Try / catch
if err := pw.Cleanup(); err != nil {
if strings.Contains(err.Error(), "failed to stop Playwright") {
// check for orphaned driver processes; don't mask the original error
}
} Prevention
- Make Cleanup idempotent with sync.Once
- Upgrade playwright-go regularly for driver lifecycle fixes
- After shutdown errors, sweep orphaned node/chromium processes
- Log Stop failures at warning level instead of failing shutdown
When it happens
Trigger: pw.PW.Stop() returns an error during Cleanup — driver process already exited (e.g. after a browser crash), broken pipe to the driver, or Stop racing a concurrent Cleanup.
Common situations: Shutdown after Chromium crashed taking the driver with it; SIGTERM handling that calls Cleanup while the driver is mid-operation; test suites leaking drivers when this path fails.
Related errors
- failed to close Playwright browser: %w
- failed to launch Chromium: %w
- failed to start new Playwright browser context: %w
- failed to start new Playwright page: %w
- failed to install Playwright: %w
AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31).
Data as JSON: /api/errors/ec42647d3c85b41f.
Report an issue: GitHub.