jamiepine/voicebox · error · ValueError

Preset profile {profile.id} is missing preset engine metadat

Error message

Preset profile {profile.id} is missing preset engine metadata

What it means

Raised by validate_profile_engine when profile.voice_type == 'preset' but either preset_engine or preset_voice_id is unset (profiles.py:117-121). A preset profile is identified by these two fields — a preset row missing them is malformed and cannot be used with any engine. This is a data-integrity failure, not a misuse of the API.

Source

Thrown at backend/services/profiles.py:121

        return None

    if preset_engine or preset_voice_id:
        return "Cloned profiles cannot set preset_engine or preset_voice_id"
    if design_prompt:
        return "Cloned profiles cannot set design_prompt"
    if default_engine and default_engine not in CLONING_ENGINES:
        return f"Cloned profiles cannot use default engine '{default_engine}'"
    return None


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,

View on GitHub (pinned to 51f49dea19)

Solutions

  1. Backfill the missing fields: UPDATE voice_profiles SET preset_engine='<engine>', preset_voice_id='<vid>' WHERE id='<id>';.
  2. If the row is not actually a preset, set voice_type to 'cloned' or 'designed' as appropriate and clear the preset fields.
  3. Audit the create_profile path to confirm preset_engine and preset_voice_id are required when voice_type='preset'.
  4. Add a DB-level CHECK constraint so this cannot recur.

Example fix

-- before: preset row missing metadata
SELECT voice_type, preset_engine, preset_voice_id FROM voice_profiles WHERE id='<id>';
-- voice_type=preset, preset_engine=NULL
-- after
UPDATE voice_profiles SET preset_engine='qwen', preset_voice_id='voice-1' WHERE id='<id>';
Defensive patterns

Strategy: type-guard

Validate before calling

def preset_profile_complete(profile) -> bool:
    return (
        getattr(profile, 'voice_type', None) == 'preset'
        and bool(getattr(profile, 'preset_engine', None))
        and bool(getattr(profile, 'preset_voice_id', None))
    )

# before validate_profile_engine:
if profile.voice_type == 'preset' and not preset_profile_complete(profile):
    raise HTTPException(409, f'Profile {profile.id} is malformed: preset metadata missing.')

Type guard

def is_complete_preset(profile) -> bool:
    return (
        getattr(profile, 'voice_type', None) == 'preset'
        and isinstance(getattr(profile, 'preset_engine', None), str) and bool(profile.preset_engine)
        and isinstance(getattr(profile, 'preset_voice_id', None), str) and bool(profile.preset_voice_id)
    )

Try / catch

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

Prevention

When it happens

Trigger: A profile row was inserted with voice_type='preset' but preset_engine/preset_voice_id left null (manual SQL, a migration that set voice_type without backfilling the metadata, or a bug in create_profile).

Common situations: Schema migration introduced voice_type and classified some rows as 'preset' without populating the engine fields; an admin edited the row directly; a copy-paste between profiles dropped the fields.

Related errors


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