Billionmail/BillionMail · error
create output dir: %w
Error message
create output dir: %w
What it means
CaptureScreenshots first ensures cfg.OutputDir exists via os.MkdirAll. If that fails (permissions, read-only filesystem, path is a file, invalid path), it wraps the OS error with 'create output dir: %w'.
Source
Thrown at core/internal/service/video_gen/screenshots.go:56
// DefaultScreenshotConfig returns config with sensible defaults.
func DefaultScreenshotConfig(websiteURL, businessName, outputDir string) ScreenshotConfig {
return ScreenshotConfig{
WebsiteURL: websiteURL,
BusinessName: businessName,
OutputDir: outputDir,
Width: 1920,
Height: 1080,
Timeout: 30 * time.Second,
}
}
// CaptureScreenshots takes 3 screenshots of the prospect's web presence:
// homepage, contact/scheduling page, and Google Maps listing.
// Requires: npx playwright (Node.js + Playwright installed).
func CaptureScreenshots(ctx context.Context, cfg ScreenshotConfig) (*ScreenshotResult, error) {
if err := os.MkdirAll(cfg.OutputDir, 0755); err != nil {
return nil, fmt.Errorf("create output dir: %w", err)
}
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 {View on GitHub (pinned to fc36c76c05)
Solutions
- Check the wrapped OS error (permission denied / not a directory / no space) for the exact cause
- Ensure the output directory path is writable by the process user (chown/chmod or run with correct UID)
- Mount a writable volume at the output path in containerized deployments
- Verify OutputDir is a directory path, not an existing file
Example fix
// before
cfg := ScreenshotConfig{OutputDir: "/var/lib/app/shots"}
// after
if err := os.MkdirAll("/var/lib/app/shots", 0o755); err != nil {
log.Fatalf("output dir not writable: %v", err)
}
cfg := ScreenshotConfig{OutputDir: "/var/lib/app/shots"} Defensive patterns
Strategy: validation
Validate before calling
func ensureWritableDir(path string) error {
info, err := os.Stat(path)
if err == nil && !info.IsDir() {
return fmt.Errorf("%s is a file, not a directory", path)
}
if err := os.MkdirAll(path, 0o755); err != nil {
return err
}
f, err := os.CreateTemp(path, ".writecheck")
if err != nil {
return err
}
f.Close(); os.Remove(f.Name())
return nil
} Try / catch
res, err := CaptureScreenshots(ctx, cfg)
if err != nil && strings.HasPrefix(err.Error(), "create output dir:") {
var perr *fs.PathError
if errors.As(err, &perr) && errors.Is(perr.Err, fs.ErrPermission) {
return fmt.Errorf("fix permissions or volume mount for %s", cfg.OutputDir)
}
} Prevention
- Mount a writable volume for all output directories in Docker
- Run the process with a UID that owns the output directory
- Pre-create output dirs in the deployment/Dockerfile
- Use absolute paths for OutputDir to avoid surprises from working-directory changes
When it happens
Trigger: os.MkdirAll(cfg.OutputDir, 0755) returns an error: parent dirs not writable, OutputDir exists as a regular file, disk full, or a relative path that resolves outside a read-only container layer.
Common situations: Running the pipeline in Docker with a read-only root filesystem and no volume mounted for output; OutputDir pointing at an existing file; running as non-root user without write permission to the configured path.
Related errors
- create thumbnail dir: %w
- error reading project configuration file: %v
- error writing project configuration file: %v
- error writing knowledge base file: %v
- error reading knowledge base directory: %v
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/7fbcaf222a1b18e6.
Report an issue: GitHub.