Billionmail/BillionMail · error
create output dir: %w
Error message
create output dir: %w
What it means
CompositeVideo creates the output directory (os.MkdirAll on filepath.Dir(cfg.OutputPath)) before running ffmpeg. If directory creation fails, the error is wrapped as 'create output dir: %w' and compositing is aborted, since ffmpeg would otherwise fail writing the output file. The wrapped cause is the standard filesystem error (permission denied, path is a file, etc.).
Source
Thrown at core/internal/service/video_gen/composite.go:190
pipY := cfg.Height - pipH - 20
return fmt.Sprintf(
"[%d:v]scale=%d:%d[pip];[%s][pip]overlay=%d:%d:shortest=1[vpip]",
lipSyncIdx, pipW, pipH, baseVideo, pipX, pipY,
)
}
// CompositeVideo runs FFmpeg to combine screenshots + audio into a final video.
// Requires: ffmpeg installed and in PATH.
func CompositeVideo(ctx context.Context, cfg CompositeConfig) (*CompositeResult, error) {
args := BuildFFmpegArgs(cfg)
if args == nil {
return nil, fmt.Errorf("no scenes provided")
}
// Ensure output directory exists
if err := os.MkdirAll(filepath.Dir(cfg.OutputPath), 0755); err != nil {
return nil, fmt.Errorf("create output dir: %w", err)
}
cmd := exec.CommandContext(ctx, "ffmpeg", args...)
out, err := cmd.CombinedOutput()
if err != nil {
return nil, fmt.Errorf("ffmpeg compositing failed: %w\noutput: %s", err, string(out))
}
// Calculate total duration from scenes
var totalDuration time.Duration
for _, scene := range cfg.Scenes {
totalDuration += scene.Duration
}
return &CompositeResult{
VideoPath: cfg.OutputPath,
Duration: totalDuration,
}, nilView on GitHub (pinned to fc36c76c05)
Solutions
- Read the wrapped cause (e.g. 'permission denied') and fix filesystem permissions on the output parent directory
- Verify cfg.OutputPath's directory component is not an existing file; remove or rename it
- Ensure the container/volume is writable (mount a writable volume, don't write into a read-only layer)
- Check disk space and mount status if the output volume is a network mount
Example fix
// before
cfg := video_gen.CompositeConfig{OutputPath: "/out/final.mp4"} // /out not writable
// after
cfg := video_gen.CompositeConfig{OutputPath: "/tmp/video-out/final.mp4"} // writable dir
os.MkdirAll("/tmp/video-out", 0o755) Defensive patterns
Strategy: validation
Validate before calling
dir := filepath.Dir(cfg.OutputPath)
if info, err := os.Stat(dir); err == nil && !info.IsDir() {
return fmt.Errorf("%s exists and is not a directory", dir)
}
if err := os.MkdirAll(dir, 0o755); err != nil {
return fmt.Errorf("output dir not creatable: %w", err)
} Try / catch
res, err := video_gen.CompositeVideo(ctx, cfg)
if err != nil {
if strings.Contains(err.Error(), "create output dir") && strings.Contains(err.Error(), "permission denied") {
return fmt.Errorf("fix write permissions on %s: %w", filepath.Dir(cfg.OutputPath), err)
}
return err
} Prevention
- Mount a writable volume for video output in containers; never write into read-only layers
- Ensure the service user owns or can write to the output root directory
- Verify the output path's parent is not an existing file
- Check disk space and mount health for network volumes before long encode jobs
When it happens
Trigger: os.MkdirAll(filepath.Dir(cfg.OutputPath), 0755) fails — parent path is an existing regular file, no write permission on the parent directory, read-only filesystem, or invalid path characters.
Common situations: OutputPath pointing inside a read-only container filesystem; a file existing where a directory is expected; running as non-root user without permission on the output root; NFS/mounted volume unavailable.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 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/bcfc5d1a15498fe0.
Report an issue: GitHub.