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
- Set a personality prompt on the profile: PATCH /profiles/{id} with a non-empty personality string.
- If you hit this from the Compose button, hide/disable it in the UI when profile.personality is empty.
- For rewrite flows, either set a personality or call generate without personality=true.
- 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
- Disable the Compose button in the UI when profile.personality is empty.
- Require personality at profile-create time for profiles intended for personality flows.
- Backfill legacy cloned profiles with a default personality.
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
- Rewrite needs non-empty text to restate.
- Unknown LLM engine: {engine}. Supported: {list(LLM_ENGINES.k
- LLM produced empty output; nothing to speak.
- Invalid LLM size '{model_size}'. Must be one of: {sorted(val
- Each example must be a [user, assistant] pair
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/1c7a93cea12a0d33.
Report an issue: GitHub.