fix(voices): #1219 review — close the /use dedup race + generic materialize error

- /archetypes/{id}/use: re-check the personality row inside the write connection
  right before INSERT (the pre-render SELECT could race a concurrent /use of the
  same archetype). Reuse the winner's row and drop the just-rendered sample. A
  UNIQUE index isn't viable — marketplace/persona imports reuse the personality
  column — so this closes the realistic single-user window (greptile P2).
- VoiceSelector: log the raw materialize error to the console and show a generic,
  actionable localized message instead of interpolating backend detail; drop the
  {{message}} placeholder from voiceSelector.addVoiceFailed across all 21 locales
  (CodeRabbit).
This commit is contained in:
debpalash
2026-07-21 05:31:22 +05:30
parent bb63a88956
commit f368a05987
23 changed files with 40 additions and 23 deletions
+15
View File
@@ -341,6 +341,21 @@ async def use_archetype(archetype_id: str, name: Optional[str] = Query(None)):
profile_name = (name or a["name"]).strip() or a["name"]
try:
with db_conn() as conn:
# Re-check under the write connection right before inserting: a
# concurrent /use for the same archetype may have inserted while we
# were rendering (the pre-render SELECT above raced). Reuse that row
# and drop our just-rendered sample instead of creating a duplicate.
# (personality is NOT globally unique — marketplace/persona imports
# reuse the column — so a UNIQUE index isn't an option; this closes
# the realistic window for the single-user desktop app.)
dup = conn.execute(
"SELECT id, name FROM voice_profiles WHERE personality = ? LIMIT 1",
(a["id"],),
).fetchone()
if dup is not None:
with __import__("contextlib").suppress(OSError):
os.remove(audio_path)
return {"profile_id": dup["id"], "name": dup["name"]}
conn.execute(
"INSERT INTO voice_profiles "
"(id, name, ref_audio_path, ref_text, instruct, language, seed, personality, created_at) "
+4 -2
View File
@@ -252,8 +252,10 @@ export default function VoiceSelector({
setJustMaterialized({ id: r.profile_id, name: r.name });
onChange?.(r.profile_id);
} catch (e) {
// Keep the previous value; just tell the user it didn't take.
toast.error(t('voiceSelector.addVoiceFailed', { message: e?.message || String(e) }));
// Keep the previous value; tell the user it didn't take with an
// actionable, non-technical message (the raw error goes to the console).
console.error('[VoiceSelector] failed to add gallery voice', e);
toast.error(t('voiceSelector.addVoiceFailed'));
} finally {
setMaterializing(false);
}
+1 -1
View File
@@ -2229,7 +2229,7 @@
"createVoice": "إنشاء صوت جديد",
"gallery": "المعرض",
"addingVoice": "جارٍ إضافة الصوت…",
"addVoiceFailed": "تعذّرت إضافة هذا الصوت: {{message}}"
"addVoiceFailed": "تعذّرت إضافة هذا الصوت"
},
"remote_gate": {
"title": "أدخل رقم التعريف الشخصي للوصول",
+1 -1
View File
@@ -2229,7 +2229,7 @@
"createVoice": "Erstellen Sie eine neue Stimme",
"gallery": "Galerie",
"addingVoice": "Stimme wird hinzugefügt…",
"addVoiceFailed": "Diese Stimme konnte nicht hinzugefügt werden: {{message}}"
"addVoiceFailed": "Diese Stimme konnte nicht hinzugefügt werden"
},
"remote_gate": {
"title": "Zugangs-PIN eingeben",
+1 -1
View File
@@ -2513,7 +2513,7 @@
"createVoice": "Create a new voice",
"gallery": "Gallery",
"addingVoice": "Adding voice…",
"addVoiceFailed": "Couldn't add that voice: {{message}}"
"addVoiceFailed": "Couldn't add that voice — please try again."
},
"sharing": {
"title": "Sharing & Remote Access",
+1 -1
View File
@@ -2229,7 +2229,7 @@
"createVoice": "Crea una nueva voz",
"gallery": "Galería",
"addingVoice": "Añadiendo voz…",
"addVoiceFailed": "No se pudo añadir esa voz: {{message}}"
"addVoiceFailed": "No se pudo añadir esa voz"
},
"remote_gate": {
"title": "Introduce el PIN de acceso",
+1 -1
View File
@@ -2229,7 +2229,7 @@
"createVoice": "Créer une nouvelle voix",
"gallery": "Galerie",
"addingVoice": "Ajout de la voix…",
"addVoiceFailed": "Impossible d'ajouter cette voix : {{message}}"
"addVoiceFailed": "Impossible d'ajouter cette voix"
},
"remote_gate": {
"title": "Saisir le code PIN d'accès",
+1 -1
View File
@@ -2229,7 +2229,7 @@
"createVoice": "एक नई आवाज बनाएं",
"gallery": "गैलरी",
"addingVoice": "आवाज़ जोड़ी जा रही है…",
"addVoiceFailed": "वह आवाज़ नहीं जोड़ी जा सकी: {{message}}"
"addVoiceFailed": "वह आवाज़ नहीं जोड़ी जा सकी"
},
"remote_gate": {
"title": "एक्सेस पिन दर्ज करें",
+1 -1
View File
@@ -2229,7 +2229,7 @@
"createVoice": "Ciptakan suara baru",
"gallery": "Galeri",
"addingVoice": "Menambahkan suara…",
"addVoiceFailed": "Tidak dapat menambahkan suara itu: {{message}}"
"addVoiceFailed": "Tidak dapat menambahkan suara itu"
},
"remote_gate": {
"title": "Masukkan PIN akses",
+1 -1
View File
@@ -2229,7 +2229,7 @@
"createVoice": "Crea una nuova voce",
"gallery": "Galleria",
"addingVoice": "Aggiunta voce…",
"addVoiceFailed": "Impossibile aggiungere quella voce: {{message}}"
"addVoiceFailed": "Impossibile aggiungere quella voce"
},
"remote_gate": {
"title": "Inserisci il PIN di accesso",
+1 -1
View File
@@ -2229,7 +2229,7 @@
"createVoice": "新しい音声を作成する",
"gallery": "ギャラリー",
"addingVoice": "音声を追加中…",
"addVoiceFailed": "その音声を追加できませんでした: {{message}}"
"addVoiceFailed": "その音声を追加できませんでした"
},
"remote_gate": {
"title": "アクセスPINを入力してください",
+1 -1
View File
@@ -2229,7 +2229,7 @@
"createVoice": "새 목소리 만들기",
"gallery": "갤러리",
"addingVoice": "음성 추가 중…",
"addVoiceFailed": "해당 음성을 추가할 수 없습니다: {{message}}"
"addVoiceFailed": "해당 음성을 추가할 수 없습니다"
},
"remote_gate": {
"title": "액세스 PIN을 입력하세요.",
+1 -1
View File
@@ -2229,7 +2229,7 @@
"createVoice": "Creëer een nieuwe stem",
"gallery": "Galerij",
"addingVoice": "Stem toevoegen…",
"addVoiceFailed": "Kon die stem niet toevoegen: {{message}}"
"addVoiceFailed": "Kon die stem niet toevoegen"
},
"remote_gate": {
"title": "Voer de toegangspincode in",
+1 -1
View File
@@ -2229,7 +2229,7 @@
"createVoice": "Utwórz nowy głos",
"gallery": "Galeria",
"addingVoice": "Dodawanie głosu…",
"addVoiceFailed": "Nie udało się dodać tego głosu: {{message}}"
"addVoiceFailed": "Nie udało się dodać tego głosu"
},
"remote_gate": {
"title": "Wprowadź PIN dostępu",
+1 -1
View File
@@ -2229,7 +2229,7 @@
"createVoice": "Crie uma nova voz",
"gallery": "Galeria",
"addingVoice": "Adicionando voz…",
"addVoiceFailed": "Não foi possível adicionar essa voz: {{message}}"
"addVoiceFailed": "Não foi possível adicionar essa voz"
},
"remote_gate": {
"title": "Digite o PIN de acesso",
+1 -1
View File
@@ -2229,7 +2229,7 @@
"createVoice": "Создать новый голос",
"gallery": "Галерея",
"addingVoice": "Добавление голоса…",
"addVoiceFailed": "Не удалось добавить этот голос: {{message}}"
"addVoiceFailed": "Не удалось добавить этот голос"
},
"remote_gate": {
"title": "Введите PIN-код доступа",
+1 -1
View File
@@ -2229,7 +2229,7 @@
"createVoice": "Skapa en ny röst",
"gallery": "Galleri",
"addingVoice": "Lägger till röst…",
"addVoiceFailed": "Kunde inte lägga till den rösten: {{message}}"
"addVoiceFailed": "Kunde inte lägga till den rösten"
},
"remote_gate": {
"title": "Ange åtkomst-PIN",
+1 -1
View File
@@ -2229,7 +2229,7 @@
"createVoice": "สร้างเสียงใหม่",
"gallery": "แกลเลอรี",
"addingVoice": "กำลังเพิ่มเสียง…",
"addVoiceFailed": "ไม่สามารถเพิ่มเสียงนั้นได้: {{message}}"
"addVoiceFailed": "ไม่สามารถเพิ่มเสียงนั้นได้"
},
"remote_gate": {
"title": "ป้อน PIN การเข้าถึง",
+1 -1
View File
@@ -2229,7 +2229,7 @@
"createVoice": "Yeni bir ses oluştur",
"gallery": "Galeri",
"addingVoice": "Ses ekleniyor…",
"addVoiceFailed": "Bu ses eklenemedi: {{message}}"
"addVoiceFailed": "Bu ses eklenemedi"
},
"remote_gate": {
"title": "Erişim PIN'ini girin",
+1 -1
View File
@@ -2229,7 +2229,7 @@
"createVoice": "Створіть новий голос",
"gallery": "Галерея",
"addingVoice": "Додавання голосу…",
"addVoiceFailed": "Не вдалося додати цей голос: {{message}}"
"addVoiceFailed": "Не вдалося додати цей голос"
},
"remote_gate": {
"title": "Введіть PIN-код доступу",
+1 -1
View File
@@ -2229,7 +2229,7 @@
"createVoice": "Tạo một giọng nói mới",
"gallery": "Thư viện",
"addingVoice": "Đang thêm giọng nói…",
"addVoiceFailed": "Không thể thêm giọng nói đó: {{message}}"
"addVoiceFailed": "Không thể thêm giọng nói đó"
},
"remote_gate": {
"title": "Nhập mã PIN truy cập",
+1 -1
View File
@@ -2236,7 +2236,7 @@
"createVoice": "创建新声音",
"gallery": "画廊",
"addingVoice": "正在添加声音…",
"addVoiceFailed": "无法添加该声音{{message}}"
"addVoiceFailed": "无法添加该声音"
},
"remote_gate": {
"title": "输入访问 PIN 码",
+1 -1
View File
@@ -2229,7 +2229,7 @@
"createVoice": "創造新聲音",
"gallery": "圖庫",
"addingVoice": "正在新增聲音…",
"addVoiceFailed": "無法新增該聲音{{message}}"
"addVoiceFailed": "無法新增該聲音"
},
"remote_gate": {
"title": "輸入訪問 PIN 碼",