Billionmail/BillionMail · error

create lipsync request: %w

Error message

create lipsync request: %w

What it means

BuildLipSyncRequest wraps any error returned by http.NewRequest when constructing the outbound POST to the lipsync provider (cfg.lipSyncBase()+lipSyncPath). http.NewRequest only fails on an invalid HTTP method or an unparsable URL, so this error almost always means the configured base URL is malformed or the resulting URL is invalid. The original error is preserved via %w for errors.Is/As inspection.

Source

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

		OutputDir: outputDir,
	}
}

// BuildLipSyncRequest constructs the HTTP request for lip sync generation.
// Exported for testing without making API calls.
func BuildLipSyncRequest(cfg LipSyncConfig, req LipSyncRequest) (*http.Request, error) {
	if req.Model == "" {
		req.Model = "sync-1.7.1-beta"
	}

	body, err := json.Marshal(req)
	if err != nil {
		return nil, fmt.Errorf("marshal lipsync request: %w", err)
	}

	httpReq, err := http.NewRequest("POST", cfg.lipSyncBase()+lipSyncPath, bytes.NewReader(body))
	if err != nil {
		return nil, fmt.Errorf("create lipsync request: %w", err)
	}

	httpReq.Header.Set("x-api-key", cfg.APIKey)
	httpReq.Header.Set("Content-Type", "application/json")
	return httpReq, nil
}

// BuildLipSyncStatusRequest constructs the HTTP request to check job status.
// Exported for testing.
func BuildLipSyncStatusRequest(cfg LipSyncConfig, jobID string) (*http.Request, error) {
	url := fmt.Sprintf("%s%s/%s", cfg.lipSyncBase(), lipSyncPath, jobID)
	httpReq, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, fmt.Errorf("create status request: %w", err)
	}

	httpReq.Header.Set("x-api-key", cfg.APIKey)
	return httpReq, nil

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Check the lipsync base URL configuration value (env/config) and ensure it includes a valid scheme, e.g. https://api.provider.com
  2. Trim whitespace/quotes from the configured URL before constructing LipSyncConfig
  3. Run url.Parse on the candidate base URL at config-load/startup time and fail fast with a clear message
  4. Log or unwrap the underlying error (errors.Unwrap / %v of the wrapped error) to see url.Parse's exact complaint

Example fix

// before
cfg := LipSyncConfig{BaseURL: os.Getenv("LIPSYNC_BASE_URL")} // empty -> invalid URL
// after
base := strings.TrimSpace(os.Getenv("LIPSYNC_BASE_URL"))
if u, err := url.Parse(base); err != nil || u.Scheme == "" || u.Host == "" {
    return fmt.Errorf("invalid LIPSYNC_BASE_URL %q: %w", base, err)
}
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(cfg.BaseURL)
if err != nil || u.Scheme == "" || u.Host == "" {
    return fmt.Errorf("invalid lipsync base URL %q", cfg.BaseURL)
}

Type guard

func validURL(s string) bool {
    u, err := url.Parse(s)
    return err == nil && (u.Scheme == "http" || u.Scheme == "https") && u.Host != ""
}

Try / catch

req, err := BuildLipSyncRequest(cfg, input)
if err != nil {
    return fmt.Errorf("lipsync submit aborted: %w", err)
}

Prevention

When it happens

Trigger: Calling SubmitLipSync (which calls BuildLipSyncRequest) with a LipSyncConfig whose base URL is empty, missing a scheme (e.g. "api.example.com" instead of "https://api.example.com"), or contains invalid characters, spaces, or control characters; also if lipSyncBase() concatenation produces a syntactically invalid URL.

Common situations: LIPSYNC_BASE_URL env var set incorrectly or left blank while code builds a relative URL; trailing whitespace or quotes pasted into a config file; URL containing unescaped characters like '{', '|', or a space; misconfigured YAML/JSON config where the value was never interpolated.

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/61dec5137c39a393. Report an issue: GitHub.