Billionmail/BillionMail · error
upload thumbnail: %w
Error message
upload thumbnail: %w
What it means
The thumbnail stage of UploadVideoAssets wraps UploadFile failures for thumbnailPath with 'upload thumbnail: %w', mirroring the video-stage wrapper so logs identify which asset failed. The full underlying cause (file open or R2 error) remains reachable via errors.Unwrap/errors.As.
Source
Thrown at core/internal/service/video_gen/upload.go:116
}
return &UploadResult{
Key: key,
PublicURL: BuildPublicURL(cfg, key),
}, nil
}
// UploadVideoAssets uploads the video and thumbnail to R2.
// Returns public URLs for both.
func UploadVideoAssets(ctx context.Context, cfg R2Config, videoPath, thumbnailPath, contactID string) (videoURL, thumbURL string, err error) {
videoResult, err := UploadFile(ctx, cfg, videoPath, contactID)
if err != nil {
return "", "", fmt.Errorf("upload video: %w", err)
}
thumbResult, err := UploadFile(ctx, cfg, thumbnailPath, contactID)
if err != nil {
return "", "", fmt.Errorf("upload thumbnail: %w", err)
}
return videoResult.PublicURL, thumbResult.PublicURL, nil
}
// detectContentType returns the MIME type based on file extension.
func detectContentType(filename string) string {
ext := strings.ToLower(filepath.Ext(filename))
switch ext {
case ".mp4":
return "video/mp4"
case ".webm":
return "video/webm"
case ".png":
return "image/png"
case ".jpg", ".jpeg":
return "image/jpeg"
case ".gif":View on GitHub (pinned to fc36c76c05)
Solutions
- Check the wrapped chain: if it is 'open file for upload', the thumbnail was never generated — rerun GenerateThumbnail and surface its error instead of ignoring it
- Verify the thumbnailPath matches the OutputPath returned by GenerateThumbnail
- os.Stat thumbnailPath before the upload stage and fail fast with a clear message
- If R2-side, apply the same endpoint/credential/bucket checks as the 'r2 upload' error
- Compare with the video-stage result: if video succeeded, the R2 config is fine and the problem is local to the thumbnail file
Example fix
// before
thumbResult, err := UploadFile(ctx, cfg, thumbnailPath, contactID)
if err != nil {
return "", "", fmt.Errorf("upload thumbnail: %w", err)
}
// after
if _, err := os.Stat(thumbnailPath); err != nil {
return "", "", fmt.Errorf("thumbnail file missing (was GenerateThumbnail run?): %s", thumbnailPath)
}
thumbResult, err := UploadFile(ctx, cfg, thumbnailPath, contactID)
if err != nil {
return "", "", fmt.Errorf("upload thumbnail: %w", err)
} Defensive patterns
Strategy: validation
Validate before calling
if thumbPath == "" {
return fmt.Errorf("no thumbnail: GenerateThumbnail likely failed upstream")
}
if _, err := os.Stat(thumbPath); err != nil {
return fmt.Errorf("thumbnail missing at %s", thumbPath)
} Try / catch
vURL, tURL, err := video_gen.UploadVideoAssets(ctx, cfg, videoPath, thumbPath, contactID)
if err != nil {
if strings.Contains(fmt.Sprint(err), "upload thumbnail") || errors.Is(err, os.ErrNotExist) {
log.Errorf("thumbnail stage failed: %v", err)
// re-run GenerateThumbnail before retrying the upload
}
} Prevention
- Always propagate GenerateThumbnail errors; never log-and-continue into the upload stage
- Set thumbnailPath to exactly the OutputPath GenerateThumbnail returned
- Stat the thumbnail right before UploadVideoAssets
- Add a pipeline integration test for the thumbnail-missing case (mirrors TestUploadVideoAssets_SecondFileMissing)
When it happens
Trigger: UploadFile(ctx, cfg, thumbnailPath, contactID) fails because the thumbnail file does not exist (TestUploadVideoAssets_SecondFileMissing — typically because GenerateThumbnail failed earlier) or the R2 PutObject for the thumbnail errors.
Common situations: GenerateThumbnail returned an error that was logged-and-ignored upstream, leaving no thumbnail on disk; wrong thumbnail output path configured; R2 issues that also would have failed the video upload; context cancelled between the two uploads.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- upload video: %w
- open file for upload: %w
- r2 upload: %w
- upload image failed: %s
- imagemagick thumbnail failed: %w output: %s
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/b00085c6afa9f438.
Report an issue: GitHub.