jamiepine/voicebox · error · ValueError

Designed profile {profile.id} is missing design_prompt

Error message

Designed profile {profile.id} is missing design_prompt

What it means

Raised by validate_profile_engine when profile.voice_type == 'designed' but design_prompt is missing or whitespace-only (profiles.py:128-131). A designed voice is synthesized from its design_prompt; without one the profile is malformed and the engine cannot produce the intended voice. Like error 256, this is a data-integrity failure on the row.

Source

Thrown at backend/services/profiles.py:131

def validate_profile_engine(profile, engine: str) -> None:
    voice_type = getattr(profile, "voice_type", None) or "cloned"

    if voice_type == "preset":
        preset_engine = getattr(profile, "preset_engine", None)
        preset_voice_id = getattr(profile, "preset_voice_id", None)
        if not preset_engine or not preset_voice_id:
            raise ValueError(f"Preset profile {profile.id} is missing preset engine metadata")
        if preset_engine != engine:
            raise ValueError(
                f"Preset profile {profile.id} only supports engine '{preset_engine}', not '{engine}'"
            )
        return

    if voice_type == "designed":
        design_prompt = getattr(profile, "design_prompt", None)
        if not design_prompt or not design_prompt.strip():
            raise ValueError(f"Designed profile {profile.id} is missing design_prompt")
        return

    if engine not in CLONING_ENGINES:
        raise ValueError(f"Engine '{engine}' does not support cloned voice profiles")


async def create_profile(
    data: VoiceProfileCreate,
    db: Session,
) -> VoiceProfileResponse:
    """
    Create a new voice profile.

    Args:
        data: Profile creation data
        db: Database session

    Returns:

View on GitHub (pinned to 51f49dea19)

Solutions

  1. Backfill design_prompt: UPDATE voice_profiles SET design_prompt='<text>' WHERE id='<id>';.
  2. If the row is not actually designed, set voice_type to 'cloned' or 'preset' as appropriate.
  3. Ensure create_profile requires design_prompt when voice_type='designed'.
  4. Add a DB CHECK constraint to enforce the combination.

Example fix

-- before
SELECT voice_type, design_prompt FROM voice_profiles WHERE id='<id>';
-- voice_type=designed, design_prompt=NULL
-- after
UPDATE voice_profiles SET design_prompt='warm narrator, slight rasp' WHERE id='<id>';
Defensive patterns

Strategy: type-guard

Validate before calling

def designed_profile_complete(profile) -> bool:
    dp = getattr(profile, 'design_prompt', None)
    return (
        getattr(profile, 'voice_type', None) == 'designed'
        and isinstance(dp, str) and bool(dp.strip())
    )

Type guard

def is_complete_designed(profile) -> bool:
    dp = getattr(profile, 'design_prompt', None)
    return (
        getattr(profile, 'voice_type', None) == 'designed'
        and isinstance(dp, str) and bool(dp.strip())
    )

Try / catch

try:
    validate_profile_engine(profile, engine)
except ValueError as e:
    if 'missing design_prompt' in str(e):
        raise HTTPException(409, str(e))  # data integrity
    raise HTTPException(400, str(e))

Prevention

When it happens

Trigger: A profile row was set to voice_type='designed' without a design_prompt (manual SQL, migration that reclassified rows, create_profile bug that allowed the combination); the design_prompt was cleared via an edit.

Common situations: Schema migration reclassified cloned rows as 'designed' without backfilling design_prompt; admin edited the row; a fork changed the create-time validation.

Related errors


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