Zackriya-Solutions/meetily · error · anyhow::Error

Failed to commit transaction: {}

Error message

Failed to commit transaction: {}

What it means

tx.commit() failed, so the delete+insert work rolls back and the meeting keeps its previous transcripts. On SQLite, COMMIT is where the write lock is actually exercised, so 'database is locked' (lost lock mid-transaction), disk-full while writing the journal/WAL, or the connection dying are the usual inner causes.

Source

Thrown at frontend/src-tauri/src/audio/retranscription.rs:460

    for segment in &segments {
        sqlx::query(
            "INSERT INTO transcripts (id, meeting_id, transcript, timestamp, audio_start_time, audio_end_time, duration)
             VALUES (?, ?, ?, ?, ?, ?, ?)"
        )
        .bind(&segment.id)
        .bind(&meeting_id)
        .bind(&segment.text)
        .bind(&segment.timestamp)
        .bind(segment.audio_start_time)
        .bind(segment.audio_end_time)
        .bind(segment.duration)
        .execute(&mut *tx)
        .await
        .map_err(|e| anyhow!("Failed to insert transcript: {}", e))?;
    }

    tx.commit().await
        .map_err(|e| anyhow!("Failed to commit transaction: {}", e))?;

    info!(
        "Updated {} transcripts for meeting {} in transaction",
        segments.len(),
        meeting_id
    );

    // Write updated transcripts.json and metadata.json to the meeting folder
    emit_progress(&app, &meeting_id, "saving", 90, "Writing transcript files...");

    if let Err(e) = write_transcripts_json(&folder_path, &segments) {
        warn!("Failed to write transcripts.json: {}", e);
    }

    // Find audio filename for metadata
    let audio_filename = audio_path
        .file_name()
        .and_then(|n| n.to_str())

View on GitHub (pinned to 0281737d87)

Solutions

  1. Check free disk space first - COMMIT fails hard when the journal cannot be written.
  2. Read the inner error: lock-related messages mean retrying after the competing writer exits usually succeeds.
  3. Shorten the transaction: build all rows first, then execute delete+inserts in one tight burst.
  4. Enable WAL mode and busy_timeout to make commit-time lock loss rare.
Defensive patterns

Strategy: retry

Try / catch

// Retry commit once for lock-style failures; propagate disk errors
match tx.commit().await {
    Ok(_) => {}
    Err(e) if e.to_string().contains("locked") || e.to_string().contains("busy") => {
        // rebuild and retry transaction when idle
    }
    Err(e) => return Err(anyhow!("Failed to commit transaction: {e}")),
}

Prevention

When it happens

Trigger: Another process steals the SQLite write lock between the last INSERT and COMMIT; the disk fills during a long transaction spanning hundreds of inserted segments; the DB file is deleted or the drive unmounted mid-save.

Common situations: Long meetings produce many segments, widening the lock window; machines with low disk space; another app instance writing at the same moment.

Related errors


AI-assisted analysis of Zackriya-Solutions/meetily@0281737d87 (2026-08-16). Data as JSON: /api/errors/42bf879cd7b0dc24. Report an issue: GitHub.