{"record":{"id":"17926b3797144fdb","repo":"Billionmail/BillionMail","slug":"no-voice-configured-set-voice-sample-url-or-voice","errorCode":null,"errorMessage":"no voice configured: set VOICE_SAMPLE_URL or VOICE_DEFAULT_ID","messagePattern":"no voice configured: set VOICE_SAMPLE_URL or VOICE_DEFAULT_ID","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/video_gen/orchestrator.go","lineNumber":396,"sourceCode":"func resolveVoiceID(ctx context.Context, cfg VoiceConfig) (string, error) {\n\tsampleURL := os.Getenv(\"VOICE_SAMPLE_URL\")\n\tdefaultID := os.Getenv(\"VOICE_DEFAULT_ID\")\n\n\tif sampleURL != \"\" {\n\t\tresp, err := withRetry(func() (*VoiceCloneResponse, error) {\n\t\t\treturn CloneVoice(ctx, cfg, \"sender-voice\", sampleURL)\n\t\t})\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"voice clone: %w\", err)\n\t\t}\n\t\treturn resp.ID, nil\n\t}\n\n\tif defaultID != \"\" {\n\t\treturn defaultID, nil\n\t}\n\n\treturn \"\", fmt.Errorf(\"no voice configured: set VOICE_SAMPLE_URL or VOICE_DEFAULT_ID\")\n}\n\n// pollLipSync polls lip sync status until completed or timeout.\nfunc pollLipSync(ctx context.Context, cfg LipSyncConfig, jobID string) (string, error) {\n\tdeadline := time.Now().Add(lipSyncTimeout)\n\tfor {\n\t\tif time.Now().After(deadline) {\n\t\t\treturn \"\", fmt.Errorf(\"lip sync timed out after %v\", lipSyncTimeout)\n\t\t}\n\n\t\tresp, err := CheckLipSyncStatus(ctx, cfg, jobID)\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"check lip sync status: %w\", err)\n\t\t}\n\n\t\tswitch resp.Status {\n\t\tcase \"completed\":\n\t\t\tif resp.VideoURL == \"\" {","sourceCodeStart":378,"sourceCodeEnd":414,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/video_gen/orchestrator.go#L378-L414","documentation":"resolveVoiceID resolves which voice to use for video generation. When neither a per-prospect sample URL nor the VOICE_DEFAULT_ID environment variable provides a voice ID, it returns this error instead of proceeding, because lip-sync and TTS stages cannot run without a voice.","triggerScenarios":"RunPipeline reaches the voice-resolution step while the pipeline input has an empty VoiceSampleURL and the VOICE_DEFAULT_ID environment variable is unset or empty, so the function falls through all candidates and returns the error.","commonSituations":"Deploying the video-gen service without the voice env vars configured; a prospect record missing a recorded voice sample; an .env file not loaded in Docker; typo'd env var name (VOICE_DEFAULT_ID vs VOICE_DEFAULTID).","solutions":["Set the VOICE_DEFAULT_ID environment variable to a valid voice ID from the TTS/lip-sync provider","Or provide a VoiceSampleURL on the pipeline input/prospect so a cloned voice can be created","Verify the env file is actually loaded into the container/process (docker compose env, systemd EnvironmentFile)","Add startup validation that fails fast when neither var is set"],"exampleFix":"// before\nid, err := resolveVoiceID(ctx, input)\n// after\nif input.VoiceSampleURL == \"\" && os.Getenv(\"VOICE_DEFAULT_ID\") == \"\" {\n\tlog.Fatal(\"voice not configured: set VOICE_SAMPLE_URL or VOICE_DEFAULT_ID before starting\")\n}\nid, err := resolveVoiceID(ctx, input)","handlingStrategy":"validation","validationCode":"if input.VoiceSampleURL == \"\" && os.Getenv(\"VOICE_DEFAULT_ID\") == \"\" {\n\treturn fmt.Errorf(\"pipeline requires VOICE_SAMPLE_URL or VOICE_DEFAULT_ID\")\n}","typeGuard":null,"tryCatchPattern":"id, err := resolveVoiceID(ctx, input)\nif err != nil {\n\treturn fmt.Errorf(\"voice resolution: %w\", err)\n}","preventionTips":["Set VOICE_DEFAULT_ID in every deployment environment (Docker env, CI, prod)","Validate required env vars at process startup with fail-fast checks","Require a voice sample URL in prospect onboarding so records always have a voice","Document the voice config requirements in the deployment README"],"tags":["configuration","environment-variable","voice","video-generation"],"backgroundTag":"missing-env-var","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"}