Billionmail/BillionMail · error
download lipsync video: %w
Error message
download lipsync video: %w
What it means
DownloadLipSyncVideo fetches the finished lip-sync video from the Sync Labs CDN URL via HTTP GET. This error is returned when the HTTP transport itself fails — the request never produced a response (DNS failure, connection refused/reset, TLS error, or the request context was canceled/timed out). It wraps the underlying net/http error with %w so errors.Is/As (e.g. context.DeadlineExceeded) still work.
Source
Thrown at core/internal/service/video_gen/lipsync.go:174
return nil, fmt.Errorf("decode lipsync status: %w", err)
}
return &result, nil
}
// DownloadLipSyncVideo downloads the completed lip sync video to the output directory.
func DownloadLipSyncVideo(ctx context.Context, cfg LipSyncConfig, videoURL, filename string) (string, error) {
if err := os.MkdirAll(cfg.OutputDir, 0755); err != nil {
return "", fmt.Errorf("create output dir: %w", err)
}
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)
}
View on GitHub (pinned to fc36c76c05)
Solutions
- Check outbound connectivity and DNS from the host (curl the videoURL) — the error text wraps the root cause, read the chained message.
- Verify the videoURL is fresh: re-poll CheckLipSyncStatus to get a new signed URL if the old one expired before downloading.
- Increase the caller's context deadline so long downloads are not cut off, and confirm ctx is not already canceled.
- Confirm the RateLimitedClient 'synclabs' burst/limit settings aren't causing request-drops; raise maxWait if so.
- Retry: callers already wrap this in withRetry (3 attempts, exponential backoff) — for persistent failures fix the network path, not the retry count.
Example fix
// before lipVideoURL, lipErr := pollLipSync(ctx, lipCfg, lipJobID) dlPath, lipErr := DownloadLipSyncVideo(ctx, lipCfg, lipVideoURL, "lipsync.mp4") // after // use a fresh context with an explicit download deadline instead of the long-lived pipeline ctx ctxDl, cancel := context.WithTimeout(context.Background(), 2*time.Minute) defer cancel() dlPath, lipErr := DownloadLipSyncVideo(ctxDl, lipCfg, lipVideoURL, "lipsync.mp4")
Defensive patterns
Strategy: retry
Validate before calling
// before calling
u, err := url.Parse(videoURL)
if err != nil || u.Scheme != "https" || u.Host == "" {
return fmt.Errorf("invalid video URL: %q", videoURL)
}
if ctx.Err() != nil {
return ctx.Err() // context already canceled
} Type guard
func isTransportError(err error) bool {
var ne net.Error
if errors.As(err, &ne) { return true }
return errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled) || errors.Is(err, io.ErrUnexpectedEOF)
} Try / catch
path, err := DownloadLipSyncVideo(ctx, lipCfg, lipVideoURL, "lipsync.mp4")
if err != nil {
if isTransportError(err) {
// transient: retry with backoff or re-fetch a fresh URL via CheckLipSyncStatus
}
return fmt.Errorf("download lipsync video: %w", err)
} Prevention
- Always download immediately after status becomes 'completed' — signed CDN URLs expire
- Give the download its own generous context timeout separate from polling
- Use the rate-limited client with a wait window larger than the expected download time
- Verify outbound network/DNS in the deployment environment before enabling the pipeline
When it happens
Trigger: cfg.doHTTP(req) returns a non-nil error for the GET of videoURL: network outage, unresolvable CDN hostname, the rate-limited RateLimitedClient exhausting its wait window, or ctx already canceled/expired before the download.
Common situations: Container has no outbound internet or broken DNS; Sync Labs signed video URLs have expired by the time the download happens after the 5-minute lipSyncTimeout poll; a corporate proxy/TLS MITM breaks the connection; pipeline ctx deadline expires during a long download; the rate-limited client (60s max wait) times out under burst load.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- download file failed:
- base URL not configured
- base URL accessibility test failed: %w
- circuit breaker [%s]: %w
- create lipsync request: %w
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/982dc4064216811e.
Report an issue: GitHub.