{"record":{"id":"f74c2632a69ed980","repo":"Billionmail/BillionMail","slug":"create-output-file-w","errorCode":null,"errorMessage":"create output file: %w","messagePattern":"create output file: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/video_gen/lipsync.go","lineNumber":185,"sourceCode":"\treq, err := http.NewRequestWithContext(ctx, \"GET\", videoURL, nil)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"create download request: %w\", err)\n\t}\n\n\tresp, err := cfg.doHTTP(req)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"download lipsync video: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn \"\", fmt.Errorf(\"download error %d\", resp.StatusCode)\n\t}\n\n\toutPath := filepath.Join(cfg.OutputDir, filename)\n\tf, err := os.Create(outPath)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"create output file: %w\", err)\n\t}\n\tdefer f.Close()\n\n\tif _, err := io.Copy(f, resp.Body); err != nil {\n\t\treturn \"\", fmt.Errorf(\"write video data: %w\", err)\n\t}\n\n\treturn outPath, nil\n}\n","sourceCodeStart":167,"sourceCodeEnd":195,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/video_gen/lipsync.go#L167-L195","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ndlPath, lipErr := DownloadLipSyncVideo(ctx, lipCfg, lipVideoURL, \"lipsync.mp4\")\n// after\nsafeName := filepath.Base(\"lipsync.mp4\") // strip any path components\nif err := os.MkdirAll(lipCfg.OutputDir, 0755); err != nil { /* surface early */ }\ndlPath, lipErr := DownloadLipSyncVideo(ctx, lipCfg, lipVideoURL, safeName)","handlingStrategy":"validation","validationCode":"// before calling DownloadLipSyncVideo\nif info, err := os.Stat(cfg.OutputDir); err != nil {\n\tif err := os.MkdirAll(cfg.OutputDir, 0755); err != nil {\n\t\treturn fmt.Errorf(\"output dir unusable: %w\", err)\n\t}\n} else if !info.IsDir() {\n\treturn fmt.Errorf(\"output path %s is not a directory\", cfg.OutputDir)\n}\nsafe := filepath.Base(filename)\nif safe == \".\" || safe == \"/\" || strings.ContainsAny(safe, \"\\x00\") {\n\treturn fmt.Errorf(\"invalid filename: %q\", filename)\n}","typeGuard":"func isFSError(err error) bool {\n\treturn errors.Is(err, os.ErrPermission) || errors.Is(err, syscall.ENOSPC) || errors.Is(err, os.ErrExist)\n}","tryCatchPattern":"path, err := DownloadLipSyncVideo(ctx, cfg, videoURL, filename)\nif err != nil && strings.Contains(err.Error(), \"create output file\") {\n\t// check disk space, permissions, and filename validity before retrying\n\treturn fmt.Errorf(\"cannot write to %s: %w\", cfg.OutputDir, err)\n}","preventionTips":["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"],"tags":["filesystem","io","permissions","disk-full"],"backgroundTag":"file-write-permission-denied","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}