jamiepine/voicebox · error · ValueError

This profile has no personality set. Add one on the profile

Error message

This profile has no personality set. Add one on the profile to use compose or personality-rewrite.

What it means

Raised by personality._require_personality when the profile's personality field is None or whitespace-only (personality.py:64-69). compose_as_profile and rewrite_as_profile both call this guard before touching the LLM, so the error fires before any model load. The personality prompt is what makes the character — without it, compose/rewrite is undefined behavior, so the service refuses.

Source

Thrown at backend/services/personality.py:66

    """What the three service functions return."""

    text: str
    model_size: str


def _build_system_prompt(personality: str, task: str) -> str:
    return (
        _CHARACTER_FRAMING
        + "\n\nCharacter description:\n"
        + personality.strip()
        + "\n\n"
        + task
    )


def _require_personality(personality: str | None) -> str:
    if not personality or not personality.strip():
        raise ValueError(
            "This profile has no personality set. Add one on the profile to use compose or personality-rewrite."
        )
    return personality


async def compose_as_profile(
    personality: str | None,
    model_size: str | None = None,
) -> PersonalityResult:
    """Produce a fresh utterance in the character's voice.

    No user input; the system prompt plus a trigger user turn ("Speak.")
    is all the model gets. Temperature is high so successive calls
    produce different outputs — the UI's Compose button is expected to
    be clicked repeatedly for variety.
    """
    text = _require_personality(personality)
    backend = llm_service.get_llm_model()

View on GitHub (pinned to 51f49dea19)

Solutions

  1. Set a personality prompt on the profile: PATCH /profiles/{id} with a non-empty personality string.
  2. If you hit this from the Compose button, hide/disable it in the UI when profile.personality is empty.
  3. For rewrite flows, either set a personality or call generate without personality=true.
  4. Backfill existing profiles with a default personality if the feature was added post-launch.

Example fix

# before
await compose_as_profile(profile.personality)  # personality is None
# after
await api.patch(f'/profiles/{pid}', {'personality': 'A gruff harbor master.'})
await compose_as_profile('A gruff harbor master.')
Defensive patterns

Strategy: type-guard

Validate before calling

def has_personality(profile) -> bool:
    return bool(getattr(profile, 'personality', None) and profile.personality.strip())

# before composing/rewriting:
if not has_personality(profile):
    raise HTTPException(409, 'Set a personality on this profile before using compose/rewrite.')

Type guard

def can_compose(profile) -> bool:
    p = getattr(profile, 'personality', None)
    return isinstance(p, str) and bool(p.strip())

Try / catch

try:
    result = await compose_as_profile(profile.personality)
except ValueError as e:
    if 'no personality set' in str(e):
        raise HTTPException(409, str(e))
    raise HTTPException(400, str(e))

Prevention

When it happens

Trigger: POST /profiles/{id}/compose on a profile whose personality column is null; POST /generate or /speak with personality=true against a cloned profile that never had a personality set; the personality field was cleared via an edit.

Common situations: Cloned-voice profile created before the personality feature existed; user edited the profile and blanked the personality field; UI exposes the Compose button on profiles that have no personality.

Related errors


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