Billionmail/BillionMail · error

create download request: %w

Error message

create download request: %w

What it means

DownloadLipSyncVideo builds the GET request to the completed video's CDN URL with http.NewRequestWithContext. This error wraps request-construction failure, which in practice happens only when videoURL fails Go's URL parsing — empty string, containing spaces/control characters, or otherwise malformed. It is raised locally before any network call.

Source

Thrown at core/internal/service/video_gen/lipsync.go:169

		return nil, fmt.Errorf("lipsync status API error %d: %s", resp.StatusCode, string(body))
	}

	var result LipSyncResponse
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		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()

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Guard the caller: only download when status == "completed" AND result.VideoURL is a non-empty http(s) URL.
  2. Sanitize the URL (strings.TrimSpace, url.Parse validation) before calling DownloadLipSyncVideo.
  3. If the URL is persisted, re-fetch the job status to get a fresh signed CDN URL — signed URLs can expire and be replaced.
  4. Log the offending videoURL in the caller so the malformed value is identifiable.

Example fix

// before: downloads regardless of validation
path, err := video_gen.DownloadLipSyncVideo(ctx, cfg, resp.VideoURL, name)
// after: validate before downloading
u, err := url.Parse(strings.TrimSpace(resp.VideoURL))
if err != nil || (u.Scheme != "http" && u.Scheme != "https") {
    return fmt.Errorf("invalid video URL %q", resp.VideoURL)
}
path, err := video_gen.DownloadLipSyncVideo(ctx, cfg, u.String(), name)
Defensive patterns

Strategy: validation

Validate before calling

func validVideoURL(raw string) bool {
    u, err := url.Parse(strings.TrimSpace(raw))
    return err == nil && (u.Scheme == "http" || u.Scheme == "https") && u.Host != ""
}
// call site:
if resp.Status != "completed" || !validVideoURL(resp.VideoURL) {
    return fmt.Errorf("lipsync job not downloadable (status=%q url=%q)", resp.Status, resp.VideoURL)
}

Type guard

func downloadableLipSyncResult(r *video_gen.LipSyncResponse) bool {
    return r != nil && r.Status == "completed" && validVideoURL(r.VideoURL)
}

Try / catch

path, err := video_gen.DownloadLipSyncVideo(ctx, cfg, videoURL, filename)
if err != nil {
    if strings.Contains(err.Error(), "create download request") {
        return fmt.Errorf("malformed video URL %q: %w", videoURL, err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling DownloadLipSyncVideo with an empty videoURL (e.g. caller ignored the job Status and passed the zero-value VideoURL field from LipSyncResponse), a URL with raw spaces or unescaped characters, or a video_url field from the API that is a relative path or malformed.

Common situations: Treating status=="completed" as sufficient without checking VideoURL != ""; storing the URL in a database and losing scheme/host; Sync Labs returning an error message in video_url on partially failed jobs; copy-pasted URLs with trailing whitespace.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/50e07f0eb1ef79ad. Report an issue: GitHub.