Billionmail/BillionMail · error
playwright capture failed: %w output: %s
Error message
playwright capture failed: %w output: %s
What it means
CaptureScreenshots runs a generated Node.js Playwright script via `node -e` and captures combined stdout/stderr. If the process exits non-zero, the Go error is wrapped with 'playwright capture failed: %w' plus the script's output so the Playwright-side failure is visible.
Source
Thrown at core/internal/service/video_gen/screenshots.go:75
}
result := &ScreenshotResult{
Homepage: filepath.Join(cfg.OutputDir, "homepage.png"),
Contact: filepath.Join(cfg.OutputDir, "contact.png"),
Google: filepath.Join(cfg.OutputDir, "google.png"),
}
// Build the Playwright script that captures all 3 screenshots
script := buildPlaywrightScript(cfg, result)
timeoutCtx, cancel := context.WithTimeout(ctx, cfg.Timeout)
defer cancel()
cmd := exec.CommandContext(timeoutCtx, "node", "-e", script)
cmd.Env = append(os.Environ(), "PLAYWRIGHT_BROWSERS_PATH=0")
out, err := cmd.CombinedOutput()
if err != nil {
return nil, fmt.Errorf("playwright capture failed: %w\noutput: %s", err, string(out))
}
return result, nil
}
// buildPlaywrightScript generates a Node.js script that uses Playwright to
// capture the 3 screenshots. Exported for testing command construction.
func buildPlaywrightScript(cfg ScreenshotConfig, result *ScreenshotResult) string {
contactURL := findContactURL(cfg.WebsiteURL)
googleURL := buildGoogleMapsURL(cfg.BusinessName)
return fmt.Sprintf(`
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: true });
const ctx = await browser.newContext({
viewport: { width: %d, height: %d },
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36'View on GitHub (pinned to fc36c76c05)
Solutions
- Read the 'output:' portion of the error — it contains the actual Playwright/Node stack trace
- Run `npx playwright install chromium` in the deployment image if browsers are missing
- Re-run with a longer timeout or retry for slow/unresponsive target sites
- Test the target URLs manually; blocklisted/bot-protected sites need a different capture approach
Example fix
// before
out, err := cmd.CombinedOutput()
if err != nil {
return nil, fmt.Errorf("playwright capture failed: %w\noutput: %s", err, string(out))
}
// after
out, err := cmd.CombinedOutput()
if err != nil {
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
return nil, fmt.Errorf("playwright capture timed out after %v\noutput: %s", timeout, string(out))
}
return nil, fmt.Errorf("playwright capture failed: %w\noutput: %s", err, string(out))
} Defensive patterns
Strategy: try-catch
Validate before calling
if _, err := exec.LookPath("node"); err != nil {
return fmt.Errorf("node not installed")
}
for _, u := range []string{homepageURL, contactURL, googleURL} {
if _, err := url.ParseRequestURI(u); err != nil {
return fmt.Errorf("invalid capture URL %q", u)
}
} Try / catch
res, err := CaptureScreenshots(ctx, cfg)
if err != nil && strings.Contains(err.Error(), "playwright capture failed") {
log.Printf("playwright output: %s", extractOutput(err)) // inspect Node-side trace before retrying
if isTransient(err) { return retryCapture(ctx, cfg) }
} Prevention
- Bake `npx playwright install chromium` into the deployment image
- Keep PLAYWRIGHT_BROWSERS_PATH consistent between install and runtime
- Set a per-page navigation timeout shorter than the process ctx timeout
- Pre-check prospect URLs for reachability and bot-protection before capture
When it happens
Trigger: The embedded Playwright script fails: page.goto timeout, navigation error, browser not installed, target site blocks automation or returns 4xx/5xx, or ctx deadline cancels the command.
Common situations: Playwright browsers not installed (missing `npx playwright install`); PLAYWRIGHT_BROWSERS_PATH misconfigured; prospect's website down or blocking headless browsers; 60s timeout too short for slow sites.
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/25f157dcc9bdc56a.
Report an issue: GitHub.