jamiepine/voicebox · error · HTTPException

Profile not found

Error message

Profile not found

What it means

Returned as HTTP 404 by POST /generate. The route awaits profiles.get_profile(data.profile_id) and raises this 404 when it returns None. Generation requires a voice profile (cloned, preset, designed, or import) to exist; without one, no TTS target is available.

Source

Thrown at backend/routes/generations.py:67

    return row


def _resolve_generation_engine(data: models.GenerationRequest, profile) -> str:
    return data.engine or getattr(profile, "default_engine", None) or getattr(profile, "preset_engine", None) or "qwen"


@router.post("/generate", response_model=models.GenerationResponse)
async def generate_speech(
    data: models.GenerationRequest,
    db: Session = Depends(get_db),
):
    """Generate speech from text using a voice profile."""
    task_manager = get_task_manager()
    generation_id = str(uuid.uuid4())

    profile = await profiles.get_profile(data.profile_id, db)
    if not profile:
        raise HTTPException(status_code=404, detail="Profile not found")

    from ..backends import engine_has_model_sizes

    engine = _resolve_generation_engine(data, profile)
    try:
        profiles.validate_profile_engine(profile, engine)
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))

    model_size = (data.model_size or "1.7B") if engine_has_model_sizes(engine) else None

    text = data.text
    source = "manual"
    if data.personality and getattr(profile, "personality", None):
        try:
            llm_result = await personality.rewrite_as_profile(profile.personality, data.text)
        except ValueError as e:
            raise HTTPException(status_code=400, detail=str(e))

View on GitHub (pinned to 51f49dea19)

Solutions

  1. Ensure at least one profile exists via GET /profiles before allowing generation.
  2. Source profile_id from a fresh profiles listing, not a cached value.
  3. On 404, refresh the profiles list and prompt the user to pick or create a profile.
  4. Validate the id format (UUID) client-side and confirm it matches a known profile.

Example fix

// before
await api.post('/generate', { profile_id: lastProfileId, text });
// after
const profiles = await api.get('/profiles');
if (!profiles.items.length) { redirect('/profiles/new'); return; }
await api.post('/generate', { profile_id: profiles.items[0].id, text });
Defensive patterns

Strategy: validation

Validate before calling

profile = await profiles.get_profile(data.profile_id, db)
if profile is None:
    raise ProfileMissing(data.profile_id)  # would 404
# safe to POST /generate

Type guard

def profile_exists(profile) -> bool:
    return profile is not None

Try / catch

try:
    client.post('/generate', json=payload)
except HTTPStatusError as e:
    if e.response.status_code == 404 and 'Profile' in e.response.json()['detail']:
        profiles = client.get('/profiles').json()
        if not profiles['items']:
            redirect('/profiles/new')
        else:
            payload['profile_id'] = profiles['items'][0]['id']
            client.post('/generate', json=payload)
        return
    raise

Prevention

When it happens

Trigger: POST /generate with a profile_id that does not exist in the VoiceProfile table; profile was deleted between UI load and submit; profile_id is empty or malformed; using a generation id or version id in the profile_id field.

Common situations: Stale profile dropdown after the profile was removed; fresh install with no profiles created yet; misconfigured client defaulting to a placeholder id; cross-environment id from a different DB.

Related errors


AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12). Data as JSON: /api/errors/2d22606247b6195d. Report an issue: GitHub.