Billionmail/BillionMail · error

decode lipsync status: %w

Error message

decode lipsync status: %w

What it means

After a 200 response, CheckLipSyncStatus decodes the body into LipSyncResponse (ID, Status, VideoURL, Error). This error wraps any json.Decode failure — malformed/truncated JSON, an HTML error page served with status 200, or a connection cut mid-body. It indicates the response was not the expected Sync Labs JSON payload despite the success status code.

Source

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

	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 {
		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)

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Log the raw response body (status 200 path) to see what was actually returned before decoding.
  2. If BaseURL points at a test mock, fix the mock to return valid LipSyncResponse JSON.
  3. Retry transient decode failures — truncation is often network-related and succeeds on the next poll.
  4. Check for proxies/interceptors between the service and the API that could rewrite the body.

Example fix

// before: decode error loses the body context
var result video_gen.LipSyncResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
    return nil, err
}
// after: capture body bytes for diagnostics, then decode
body, _ := io.ReadAll(resp.Body)
var result video_gen.LipSyncResponse
if err := json.Unmarshal(body, &result); err != nil {
    return nil, fmt.Errorf("decode lipsync status: %w (body: %q)", err, string(body))
}
Defensive patterns

Strategy: retry

Validate before calling

// inspect response before trusting decode (mocks/proxies)
// ensure test BaseURL stubs return application/json bodies like {"id":"...","status":"pending"}

Type guard

func looksLikeJSON(body []byte) bool {
    t := bytes.TrimSpace(body)
    return len(t) > 0 && (t[0] == '{' || t[0] == '[')
}
func validLipSyncStatus(r *video_gen.LipSyncResponse) bool {
    return r != nil && r.Status != ""
}

Try / catch

status, err := video_gen.CheckLipSyncStatus(ctx, cfg, jobID)
if err != nil {
    if strings.HasPrefix(err.Error(), "decode lipsync status") {
        // transient/truncated or non-JSON 200: retry after short delay,
        // and dump the raw body for diagnosis on repeated failure
    }
    return err
}
if !validLipSyncStatus(status) { return errors.New("empty lipsync status payload") }

Prevention

When it happens

Trigger: A BaseURL override (test mock) returning empty or HTML bodies with 200; a proxy/captive portal intercepting api.synclabs.so; server returning partial JSON due to premature connection close; response Content-Type changed by an intermediary.

Common situations: Integration tests where the stub returns '{}' or plain text; corporate proxy rewriting responses; transient network truncation during long polls; Sync Labs API version change altering the payload shape (though Decode tolerates missing fields).

Related errors


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