{"record":{"id":"5e8d58ff260a954e","repo":"Zackriya-Solutions/meetily","slug":"failed-to-start-transaction-5e8d58","errorCode":null,"errorMessage":"Failed to start transaction: {}","messagePattern":"Failed to start transaction: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"frontend/src-tauri/src/audio/retranscription.rs","lineNumber":434,"sourceCode":"        return Err(anyhow!(\"Retranscription cancelled\"));\n    }\n\n    emit_progress(&app, &meeting_id, \"saving\", 80, \"Saving transcripts...\");\n\n    // Create transcript segments with proper timestamps from VAD\n    let segments = create_transcript_segments(&all_transcripts);\n\n    // Save to database\n    let app_state = app\n        .try_state::<AppState>()\n        .ok_or_else(|| anyhow!(\"App state not available\"))?;\n\n    // Wrap delete+insert+update in a transaction to prevent data loss\n    let pool = app_state.db_manager.pool();\n    let mut conn = pool.acquire().await.map_err(|e| anyhow!(\"DB error: {}\", e))?;\n    let mut tx = sqlx::Connection::begin(&mut *conn)\n        .await\n        .map_err(|e| anyhow!(\"Failed to start transaction: {}\", e))?;\n\n    sqlx::query(\"DELETE FROM transcripts WHERE meeting_id = ?\")\n        .bind(&meeting_id)\n        .execute(&mut *tx)\n        .await\n        .map_err(|e| anyhow!(\"Failed to delete existing transcripts: {}\", e))?;\n\n    for segment in &segments {\n        sqlx::query(\n            \"INSERT INTO transcripts (id, meeting_id, transcript, timestamp, audio_start_time, audio_end_time, duration)\n             VALUES (?, ?, ?, ?, ?, ?, ?)\"\n        )\n        .bind(&segment.id)\n        .bind(&meeting_id)\n        .bind(&segment.text)\n        .bind(&segment.timestamp)\n        .bind(segment.audio_start_time)\n        .bind(segment.audio_end_time)","sourceCodeStart":416,"sourceCodeEnd":452,"githubUrl":"https://github.com/Zackriya-Solutions/meetily/blob/0281737d87d26352fb0adc78c8c0975f691b23d1/frontend/src-tauri/src/audio/retranscription.rs#L416-L452","documentation":"A pooled connection was acquired, but issuing BEGIN failed. On SQLite this is nearly always SQLITE_BUSY at BEGIN time - another connection already holds the single write lock - or the connection was left in a bad state by an earlier error on it.","triggerScenarios":"Another task opens a write transaction (import saving, live transcript writes, summary update) at the exact moment retranscription starts its delete+insert transaction; nested or abandoned transactions on the same connection.","commonSituations":"Simultaneous DB-heavy operations finishing at the same time; a background sync task that writes during retranscription save.","solutions":["Read the inner error: 'database is locked' means retry after the concurrent writer finishes.","Serialize database writers through a single writer queue or task so only one transaction is open at a time.","Enable busy_timeout/WAL on the pool so BEGIN waits for the lock instead of erroring.","Retry the retranscription once the other operation completes."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Retry the whole short transaction once on BEGIN failure\nlet tx = match sqlx::Connection::begin(&mut *conn).await {\n    Ok(t) => t,\n    Err(e) => {\n        tokio::time::sleep(std::time::Duration::from_millis(500)).await;\n        sqlx::Connection::begin(&mut *conn).await?\n    }\n};","preventionTips":["Serialize all database writers (single writer task or queue) to avoid concurrent BEGIN.","Enable busy_timeout on the SQLite connection string/options.","Keep write transactions short: prepare all rows first, then write in one burst."],"tags":["sqlx","sqlite","transaction","database-locked"],"backgroundTag":"database-transaction-begin-failed","analyzedSha":"0281737d87d26352fb0adc78c8c0975f691b23d1","analyzedAt":"2026-08-16T20:57:52.567Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}