{"record":{"id":"5bb97d3def80b1c4","repo":"jamiepine/voicebox","slug":"no-voice-profile-resolved-pass-profile-name-or","errorCode":null,"errorMessage":"No voice profile resolved. Pass `profile` (name or id), or configure a default in Voicebox → Settings → MCP.","messagePattern":"No voice profile resolved\\. Pass `profile` \\(name or id\\), or configure a default in Voicebox → Settings → MCP\\.","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"backend/routes/speak.py","lineNumber":47,"sourceCode":"    data: models.SpeakRequest,\n    request: Request,\n    db: Session = Depends(get_db),\n):\n    \"\"\"Speak text in a voice profile. Mirrors voicebox.speak (MCP).\n\n    Response shape matches POST /generate — a ``GenerationResponse`` with\n    ``status=\"generating\"`` and an ``id`` the caller polls at\n    ``GET /generate/{id}/status``.\n    \"\"\"\n    client_id = request.headers.get(\"X-Voicebox-Client-Id\")\n    profile = resolve_profile(data.profile, client_id, db)\n    if profile is None:\n        if data.profile:\n            raise HTTPException(\n                status_code=404,\n                detail=f\"Voice profile '{data.profile}' not found.\",\n            )\n        raise HTTPException(\n            status_code=400,\n            detail=(\n                \"No voice profile resolved. Pass `profile` (name or id), \"\n                \"or configure a default in Voicebox → Settings → MCP.\"\n            ),\n        )\n\n    binding = None\n    if client_id:\n        binding = (\n            db.query(MCPClientBinding)\n            .filter(MCPClientBinding.client_id == client_id)\n            .first()\n        )\n\n    # Resolve per-client personality default when the caller didn't pin it.\n    personality_flag = data.personality\n    if personality_flag is None and binding is not None:","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/backend/routes/speak.py#L29-L65","documentation":"Returned by POST /speak when resolve_profile returns None AND data.profile is empty/None (HTTP 400). The handler treats 'no identifier supplied and no default resolvable' as a client error distinct from a not-found. The message directs the user to either pass profile or set an MCP default in settings.","triggerScenarios":"POST /speak with profile omitted/null and no MCP default configured for the client. First-time use before any default is set, or after the default binding was cleared.","commonSituations":"New Voicebox client that has not configured a default profile. Client_id not sent (no X-Voicebox-Client-Id header) so no binding could be looked up, and profile omitted.","solutions":["Always pass profile (name or id) in the request body when no default is configured.","Configure a default profile in Voicebox → Settings → MCP for the given client.","Ensure the X-Voicebox-Client-Id header is sent so the binding lookup can resolve a default.","In the client, detect 'no profile' state and prompt selection before calling /speak."],"exampleFix":"// before\n{ \"text\": \"hi\" }  // profile omitted, no default\n\n// after\n{ \"text\": \"hi\", \"profile\": \"default-narrator\" }","handlingStrategy":"validation","validationCode":"function speakPayloadOk(profile, clientId) {\n  if (profile) return true;\n  return !!clientId; // default binding only resolvable when client_id is sent\n}","typeGuard":"function hasSpeakTarget(profile, clientId) { return !!profile || !!clientId; }","tryCatchPattern":"try { await api.post('/speak', { text }); }\ncatch (e) { if (e.response?.status === 400) promptForProfile(); throw e; }","preventionTips":["Always send profile when no MCP default is configured.","Include the X-Voicebox-Client-Id header so a default binding can resolve.","Configure a default profile in Settings → MCP for each client."],"tags":["fastapi","http","validation","speak","profiles","mcp","rest"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}