{"record":{"id":"e58d8808137e7cd4","repo":"Billionmail/BillionMail","slug":"write-audio-data-w","errorCode":null,"errorMessage":"write audio data: %w","messagePattern":"write audio data: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/video_gen/voice.go","lineNumber":206,"sourceCode":"\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"cartesia TTS API call: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\tbody, _ := io.ReadAll(resp.Body)\n\t\treturn \"\", fmt.Errorf(\"cartesia TTS API error %d: %s\", resp.StatusCode, string(body))\n\t}\n\n\toutPath := filepath.Join(cfg.OutputDir, filename)\n\tf, err := os.Create(outPath)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"create output file: %w\", err)\n\t}\n\tdefer f.Close()\n\n\tif _, err := io.Copy(f, resp.Body); err != nil {\n\t\treturn \"\", fmt.Errorf(\"write audio data: %w\", err)\n\t}\n\n\treturn outPath, nil\n}\n","sourceCodeStart":188,"sourceCodeEnd":211,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/video_gen/voice.go#L188-L211","documentation":"Once the WAV file is created, TextToSpeech streams the audio with io.Copy(f, resp.Body). If the copy fails — the Cartesia connection drops mid-transfer, a read timeout on the response body, or a disk write error — the cause is wrapped as 'write audio data'. The result is a partial or zero-byte WAV file at outPath.","triggerScenarios":"Cartesia closes the connection before the full audio streams, RateLimitedClient read timeout expires mid-body, ctx is cancelled during transfer, or the disk fills while writing.","commonSituations":"Long transcripts producing large audio over flaky networks, aggressive HTTP client timeouts, small disk volumes in containers, LB/proxy idle timeouts cutting long responses.","solutions":["Inspect the wrapped error: read/write vs network; retry on network-side failures.","Increase HTTP client response-header/body read timeouts for long audio.","Check free disk space and filesystem health on OutputDir.","Delete the partial file on failure so callers don't consume truncated audio.","Verify the produced file is non-empty and a valid WAV before returning."],"exampleFix":"// before\nif _, err := io.Copy(f, resp.Body); err != nil {\n    return \"\", fmt.Errorf(\"write audio data: %w\", err)\n}\nreturn outPath, nil\n// after\nif _, err := io.Copy(f, resp.Body); err != nil {\n    f.Close()\n    os.Remove(outPath)\n    return \"\", fmt.Errorf(\"write audio data: %w\", err)\n}\nif err := f.Close(); err != nil {\n    os.Remove(outPath)\n    return \"\", fmt.Errorf(\"close audio file: %w\", err)\n}\nreturn outPath, nil","handlingStrategy":"try-catch","validationCode":"// pre-check: enough free space for the expected audio (rough estimate)\nconst minFreeBytes = 10 * 1024 * 1024\nif st, err := os.Statfs(cfg.OutputDir); err == nil {\n    // syscall-free alternative:\n    _ = st\n}\nvar st syscall.Statfs_t\nif err := syscall.Statfs(cfg.OutputDir, &st); err == nil {\n    free := st.Bavail * uint64(st.Bsize)\n    if free < minFreeBytes {\n        return errors.New(\"insufficient disk space for audio output\")\n    }\n}","typeGuard":null,"tryCatchPattern":"path, err := video_gen.TextToSpeech(ctx, cfg, voiceID, transcript, filename)\nif err != nil {\n    if strings.Contains(err.Error(), \"write audio data\") {\n        os.Remove(path) // clean partial file if any\n        return fmt.Errorf(\"audio transfer interrupted, retry: %w\", err)\n    }\n    return err\n}\nif info, err := os.Stat(path); err != nil || info.Size() == 0 {\n    return errors.New(\"audio file missing or empty after generation\")\n}","preventionTips":["Set generous read timeouts for large/long audio responses","Always delete partial files on failure","Verify output file size/WAV header before downstream use","Monitor disk space and LB idle timeouts for long streaming responses"],"tags":["io","network","filesystem","partial-write"],"backgroundTag":"incomplete-file-write","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}