{"record":{"id":"27836fb4e792bef9","repo":"jamiepine/voicebox","slug":"no-samples-found-for-profile-profile-id","errorCode":null,"errorMessage":"No samples found for profile {profile_id}","messagePattern":"No samples found for profile (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"backend/services/profiles.py","lineNumber":577,"sourceCode":"        }\n\n    # ── Designed profiles: return text description (future) ──\n    if voice_type == \"designed\":\n        if not profile.design_prompt or not profile.design_prompt.strip():\n            raise ValueError(f\"Designed profile {profile_id} is missing design_prompt\")\n        return {\n            \"voice_type\": \"designed\",\n            \"design_prompt\": profile.design_prompt,\n        }\n\n    if engine not in CLONING_ENGINES:\n        raise ValueError(f\"Engine '{engine}' does not support cloned voice profiles\")\n\n    # ── Cloned profiles: create from audio samples ──\n    samples = db.query(DBProfileSample).filter_by(profile_id=profile_id).all()\n\n    if not samples:\n        raise ValueError(f\"No samples found for profile {profile_id}\")\n\n    tts_model = get_tts_backend_for_engine(engine)\n\n    if len(samples) == 1:\n        sample = samples[0]\n        sample_audio_path = config.resolve_storage_path(sample.audio_path)\n        if sample_audio_path is None:\n            raise ValueError(f\"Sample audio not found for profile {profile_id}\")\n        voice_prompt, _ = await tts_model.create_voice_prompt(\n            str(sample_audio_path),\n            sample.reference_text,\n            use_cache=use_cache,\n        )\n        return voice_prompt\n\n    audio_paths = []\n    for sample in samples:\n        sample_audio_path = config.resolve_storage_path(sample.audio_path)","sourceCodeStart":559,"sourceCodeEnd":595,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/backend/services/profiles.py#L559-L595","documentation":"Raised in the cloned branch of create_voice_prompt_from_profile() when db.query(DBProfileSample).filter_by(profile_id=profile_id).all() returns an empty list. Cloned profiles are built from uploaded audio samples; with zero samples there is no source audio to clone from, so the function aborts before invoking the TTS backend.","triggerScenarios":"Creating a profile with voice_type='cloned' but never uploading samples via the sample upload endpoint; samples were deleted; profile_id belongs to a freshly created profile before any sample upload completed.","commonSituations":"User creates a profile in the UI but abandons before uploading audio; sample upload failed silently so the profile row exists without sample rows; cleanup script removed samples but not profiles; test creates a profile fixture without seeding samples.","solutions":["Upload at least one audio sample to the profile before requesting voice prompt creation.","Check the sample upload endpoint returned success and that DBProfileSample rows exist for the profile_id.","In the API layer, guard with: if not db.query(DBProfileSample).filter_by(profile_id=pid).count(): return 400 'No samples uploaded'.","If samples were lost, re-upload them; if the profile is unused, delete it."],"exampleFix":"// before\nprompt = await create_voice_prompt_from_profile(profile_id, db, engine='qwen')  // profile has no samples\n// after: ensure a sample exists first\ncount = db.query(DBProfileSample).filter_by(profile_id=profile_id).count()\nif count == 0:\n    raise HTTPException(400, \"Upload at least one audio sample first\")\nprompt = await create_voice_prompt_from_profile(profile_id, db, engine='qwen')","handlingStrategy":"validation","validationCode":"from backend.models import DBProfileSample\n\ndef has_samples(db, profile_id) -> bool:\n    return db.query(DBProfileSample).filter_by(profile_id=profile_id).count() > 0\n\nif (profile.voice_type or 'cloned') == 'cloned' and not has_samples(db, profile_id):\n    raise HTTPException(400, 'Upload at least one audio sample before synthesis')","typeGuard":null,"tryCatchPattern":"try:\n    prompt = await create_voice_prompt_from_profile(profile_id, db, engine=engine)\nexcept ValueError as e:\n    if 'No samples found' in str(e):\n        raise HTTPException(400, str(e))\n    raise","preventionTips":["Block profile creation/completion until at least one sample is uploaded for cloned profiles.","Confirm sample upload endpoints return success and persist DBProfileSample rows.","Add a UI indicator showing sample count per cloned profile."],"tags":["profiles","samples","cloning","validation","voicebox"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}