Billionmail/BillionMail · error
lipsync status API call: %w
Error message
lipsync status API call: %w
What it means
CheckLipSyncStatus polls the Sync Labs lipsync API (GET {base}/lipsync/{jobID}) to fetch a job's status. This error wraps a transport-level failure returned by the configured HTTP client (RateLimitedClient or http.DefaultClient) before any status code can be inspected. It means the request never completed successfully at the HTTP level — DNS failure, connection refused/reset, TLS error, timeout, or context cancellation.
Source
Thrown at core/internal/service/video_gen/lipsync.go:145
var result LipSyncResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return "", fmt.Errorf("decode lipsync response: %w", err)
}
return result.ID, nil
}
// CheckLipSyncStatus checks the status of a lip sync job.
func CheckLipSyncStatus(ctx context.Context, cfg LipSyncConfig, jobID string) (*LipSyncResponse, error) {
httpReq, err := BuildLipSyncStatusRequest(cfg, jobID)
if err != nil {
return nil, err
}
httpReq = httpReq.WithContext(ctx)
resp, err := cfg.doHTTP(httpReq)
if err != nil {
return nil, fmt.Errorf("lipsync status API call: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
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 {View on GitHub (pinned to fc36c76c05)
Solutions
- Verify network connectivity to the lipsync API host (curl the base URL) and fix DNS/proxy/firewall issues.
- If BaseURL is overridden for testing, confirm the mock server is running and the URL scheme/host/port are correct.
- Check whether the passed ctx was canceled or expired; give polling a context with an adequate deadline.
- Inspect the wrapped cause (%w) with errors.Is/As for net.Error, context.DeadlineExceeded, or rate-limiter exhaustion and apply the matching fix (retry with backoff, longer timeout).
Example fix
// before: pollLipSync uses a bare ctx that may expire mid-poll
status, err := video_gen.CheckLipSyncStatus(ctx, cfg, jobID)
// after: bound polling with an explicit deadline and classify the error
pollCtx, cancel := context.WithTimeout(ctx, 10*time.Minute)
defer cancel()
status, err := video_gen.CheckLipSyncStatus(pollCtx, cfg, jobID)
if err != nil {
if errors.Is(err, context.DeadlineExceeded) || isNetError(err) {
// retry with backoff
}
} Defensive patterns
Strategy: retry
Validate before calling
// pre-flight reachability check
if cfg.BaseURL != "" {
u, err := url.Parse(cfg.BaseURL)
if err != nil || u.Host == "" { return fmt.Errorf("bad lipsync BaseURL: %w", err) }
}
if err := ctx.Err(); err != nil { return err } // context already dead Type guard
func isNetError(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, syscall.ECONNREFUSED)
} Try / catch
status, err := video_gen.CheckLipSyncStatus(ctx, cfg, jobID)
if err != nil {
if isNetError(err) {
// transient: retry with exponential backoff up to N times
}
return fmt.Errorf("poll lipsync job %s: %w", jobID, err)
} Prevention
- Set a generous but bounded context deadline for the whole poll loop.
- Configure the RateLimitedClient with sane timeout and retry policy for polling traffic.
- Smoke-test BaseURL overrides with a health check before running jobs.
- Use errors.Is/As on the wrapped cause instead of string matching.
When it happens
Trigger: Calling CheckLipSyncStatus(ctx, cfg, jobID) when cfg.doHTTP returns a non-nil error: network outage, unreachable api.synclabs.so, misconfigured cfg.BaseURL (e.g. wrong port or scheme for a test stub), an expired/canceled ctx, or the RateLimitedClient giving up after exhausting retries.
Common situations: No internet/DNS in the container; SYNCLABS_API_KEY environment points at a mocked BaseURL that is not running; job polling outlives a short-lived HTTP request context; rate-limited client aborts during a traffic spike.
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
- lipsync API call: %w
- download lipsync video: %w
- base URL not configured
- failed to list containers: %w
- IPv4 network format is incorrect, please use CIDR format (e.
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/cfdb9236a72d67b6.
Report an issue: GitHub.