{"record":{"id":"bcfc5d1a15498fe0","repo":"Billionmail/BillionMail","slug":"create-output-dir-w","errorCode":null,"errorMessage":"create output dir: %w","messagePattern":"create output dir: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/video_gen/composite.go","lineNumber":190,"sourceCode":"\tpipY := cfg.Height - pipH - 20\n\n\treturn fmt.Sprintf(\n\t\t\"[%d:v]scale=%d:%d[pip];[%s][pip]overlay=%d:%d:shortest=1[vpip]\",\n\t\tlipSyncIdx, pipW, pipH, baseVideo, pipX, pipY,\n\t)\n}\n\n// CompositeVideo runs FFmpeg to combine screenshots + audio into a final video.\n// Requires: ffmpeg installed and in PATH.\nfunc CompositeVideo(ctx context.Context, cfg CompositeConfig) (*CompositeResult, error) {\n\targs := BuildFFmpegArgs(cfg)\n\tif args == nil {\n\t\treturn nil, fmt.Errorf(\"no scenes provided\")\n\t}\n\n\t// Ensure output directory exists\n\tif err := os.MkdirAll(filepath.Dir(cfg.OutputPath), 0755); err != nil {\n\t\treturn nil, fmt.Errorf(\"create output dir: %w\", err)\n\t}\n\n\tcmd := exec.CommandContext(ctx, \"ffmpeg\", args...)\n\tout, err := cmd.CombinedOutput()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"ffmpeg compositing failed: %w\\noutput: %s\", err, string(out))\n\t}\n\n\t// Calculate total duration from scenes\n\tvar totalDuration time.Duration\n\tfor _, scene := range cfg.Scenes {\n\t\ttotalDuration += scene.Duration\n\t}\n\n\treturn &CompositeResult{\n\t\tVideoPath: cfg.OutputPath,\n\t\tDuration:  totalDuration,\n\t}, nil","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/video_gen/composite.go#L172-L208","documentation":"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.).","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\ncfg := video_gen.CompositeConfig{OutputPath: \"/out/final.mp4\"} // /out not writable\n// after\ncfg := video_gen.CompositeConfig{OutputPath: \"/tmp/video-out/final.mp4\"} // writable dir\nos.MkdirAll(\"/tmp/video-out\", 0o755)","handlingStrategy":"validation","validationCode":"dir := filepath.Dir(cfg.OutputPath)\nif info, err := os.Stat(dir); err == nil && !info.IsDir() {\n    return fmt.Errorf(\"%s exists and is not a directory\", dir)\n}\nif err := os.MkdirAll(dir, 0o755); err != nil {\n    return fmt.Errorf(\"output dir not creatable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"res, err := video_gen.CompositeVideo(ctx, cfg)\nif err != nil {\n    if strings.Contains(err.Error(), \"create output dir\") && strings.Contains(err.Error(), \"permission denied\") {\n        return fmt.Errorf(\"fix write permissions on %s: %w\", filepath.Dir(cfg.OutputPath), err)\n    }\n    return err\n}","preventionTips":["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"],"tags":["filesystem","permissions","ffmpeg","io"],"backgroundTag":"permission-denied","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}