Billionmail/BillionMail · error
create output file: %w
Error message
create output file: %w
What it means
os.Create failed when creating the destination file at filepath.Join(cfg.OutputDir, filename). The output directory is created beforehand via os.MkdirAll, so this usually means a filesystem-level problem: no write permission, disk full, OutputDir pointing at a file or read-only mount, or a filename containing path separators / illegal characters.
Source
Thrown at core/internal/service/video_gen/lipsync.go:185
req, err := http.NewRequestWithContext(ctx, "GET", videoURL, nil)
if err != nil {
return "", fmt.Errorf("create download request: %w", err)
}
resp, err := cfg.doHTTP(req)
if err != nil {
return "", fmt.Errorf("download lipsync video: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("download error %d", resp.StatusCode)
}
outPath := filepath.Join(cfg.OutputDir, filename)
f, err := os.Create(outPath)
if err != nil {
return "", fmt.Errorf("create output file: %w", err)
}
defer f.Close()
if _, err := io.Copy(f, resp.Body); err != nil {
return "", fmt.Errorf("write video data: %w", err)
}
return outPath, nil
}
View on GitHub (pinned to fc36c76c05)
Solutions
- Check free disk space (df -h) — ENOSPC is the most common cause in video pipelines.
- Verify cfg.OutputDir exists as a directory and is writable by the process user; fix volume mount permissions.
- Sanitize filename: strip path separators (filepath.Base) and validate it before calling.
- Confirm nothing pre-created outPath as a directory; remove the conflicting path.
- If using a read-only container filesystem, mount a writable volume for OutputDir.
Example fix
// before
dlPath, lipErr := DownloadLipSyncVideo(ctx, lipCfg, lipVideoURL, "lipsync.mp4")
// after
safeName := filepath.Base("lipsync.mp4") // strip any path components
if err := os.MkdirAll(lipCfg.OutputDir, 0755); err != nil { /* surface early */ }
dlPath, lipErr := DownloadLipSyncVideo(ctx, lipCfg, lipVideoURL, safeName) Defensive patterns
Strategy: validation
Validate before calling
// before calling DownloadLipSyncVideo
if info, err := os.Stat(cfg.OutputDir); err != nil {
if err := os.MkdirAll(cfg.OutputDir, 0755); err != nil {
return fmt.Errorf("output dir unusable: %w", err)
}
} else if !info.IsDir() {
return fmt.Errorf("output path %s is not a directory", cfg.OutputDir)
}
safe := filepath.Base(filename)
if safe == "." || safe == "/" || strings.ContainsAny(safe, "\x00") {
return fmt.Errorf("invalid filename: %q", filename)
} Type guard
func isFSError(err error) bool {
return errors.Is(err, os.ErrPermission) || errors.Is(err, syscall.ENOSPC) || errors.Is(err, os.ErrExist)
} Try / catch
path, err := DownloadLipSyncVideo(ctx, cfg, videoURL, filename)
if err != nil && strings.Contains(err.Error(), "create output file") {
// check disk space, permissions, and filename validity before retrying
return fmt.Errorf("cannot write to %s: %w", cfg.OutputDir, err)
} Prevention
- Mount a dedicated writable volume for video output; never rely on container-local /tmp
- Monitor free disk space and clean tmpDir after jobs (the pipeline already does RemoveAll on success)
- Always sanitize external/untrusted filenames with filepath.Base
- Run the service under a user with write access to OutputDir; test with a dry-run write at startup
When it happens
Trigger: os.Create(outPath) returns an error: OutputDir is a read-only volume, the disk is full, 'filename' contains '/' (e.g. derived from a job or API value) making a nonexistent subdirectory, or the path collides with an existing directory.
Common situations: Running the container with a read-only root filesystem and tmpDir defaulting to /tmp/video_gen_<id> that got pre-created as something else; disk quota exhausted after storing many videos; filename built from untrusted input containing slashes; permission mismatch between the process user (e.g. non-root) and the mounted output volume.
Understand the failure class
Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.
Related errors
- error reading project configuration file: %v
- error writing project configuration file: %v
- error writing knowledge base file: %v
- error creating company profile file: %v
- error reading company profile file: %v
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/f74c2632a69ed980.
Report an issue: GitHub.