cjpais/Handy · critical

Failed to initialize history manager

Error message

Failed to initialize history manager

What it means

Startup panic when HistoryManager::new returns Err. The constructor creates <app_data>/recordings, opens history.db via rusqlite, migrates the legacy tauri-plugin-sql schema, then runs rusqlite_migration to latest — each step can Err: unwritable directory, unopenable/locked/corrupt database, or a migration failure when the stored user_version is newer than the binary's migrations.

Solutions

  1. If you downgraded, install the newest version again instead of running an old binary against a newer schema
  2. Back up and delete/rename history.db so a fresh database is created — history is lost but the app launches
  3. Exclude the app data dir from real-time AV scanning and sync agents to stop file locks
  4. Free disk space and repair permissions on the app data dir

Example fix

// before
let history_manager =
    Arc::new(HistoryManager::new(app_handle).expect("Failed to initialize history manager"));

// after — history is non-critical: degrade instead of aborting startup
let history_manager = Arc::new(match HistoryManager::new(app_handle) {
    Ok(m) => m,
    Err(e) => {
        log::error!("history disabled this session: {e:#}");
        HistoryManager::new_disabled()
    }
});
Defensive patterns

Strategy: fallback

Validate before calling

// Optional pre-flight: open the db read-only to detect lock/corruption early
match rusqlite::Connection::open_with_flags(
    app_data.join("history.db"),
    rusqlite::OpenFlags::SQLITE_OPEN_READ_WRITE,
) {
    Ok(_) => {}
    Err(e) => log::warn!("history db may be locked/corrupt: {e}"),
}

Try / catch

match HistoryManager::new(app_handle) {
    Ok(m) => m,
    Err(e) if e.to_string().contains("user_version") => {
        // schema newer than binary: refuse with a clear message, offer app update
    }
    Err(_) => {
        // quarantine: rename history.db to history.db.bak and retry once with a fresh db
    }
}

Prevention

When it happens

Trigger: Startup calling HistoryManager::new: create_dir_all on recordings fails; Connection::open fails (disk I/O error, file locked by another process); migrate_from_tauri_plugin_sql or Migrations::to_latest fails (schema ahead of the binary, or corrupted schema).

Common situations: Downgrading the app after running a newer version (schema user_version ahead of the older binary); history.db corrupted after a crash or power loss; antivirus or sync clients (OneDrive/Dropbox) locking history.db; disk full; app data permissions broken.

Related errors


AI-assisted analysis of cjpais/Handy@ba10ce1943 (2026-08-17). Data as JSON: /api/errors/434d2b0c64a5dd0a. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/src/lib.rs:206

    // The frontend is responsible for calling the `initialize_enigo` command
    // after onboarding completes. This avoids triggering permission dialogs
    // on macOS before the user is ready.

    // Initialize the managers. The audio recorder receives the streaming router
    // explicitly, so always-on microphone startup can wire live-preview frames
    // even before Tauri state is populated.
    let model_manager =
        Arc::new(ModelManager::new(app_handle).expect("Failed to initialize model manager"));
    let transcription_manager = Arc::new(
        TranscriptionManager::new(app_handle, model_manager.clone())
            .expect("Failed to initialize transcription manager"),
    );
    let recording_manager = Arc::new(
        AudioRecordingManager::new(app_handle, transcription_manager.stream_router())
            .expect("Failed to initialize recording manager"),
    );
    let history_manager =
        Arc::new(HistoryManager::new(app_handle).expect("Failed to initialize history manager"));

    // Initialize the transcribe-cpp native backend (logging + backend module
    // registration) once, before any whisper model is loaded.
    managers::transcription::init_transcribe_backend();

    // Apply accelerator preferences before any model loads
    managers::transcription::apply_accelerator_settings(app_handle);

    // Add managers to Tauri's managed state
    app_handle.manage(recording_manager.clone());
    app_handle.manage(model_manager.clone());
    app_handle.manage(transcription_manager.clone());
    app_handle.manage(history_manager.clone());
    app_handle.manage(tray::TrayState::new());

    // Note: Shortcuts are NOT initialized here.
    // The frontend is responsible for calling the `initialize_shortcuts` command
    // after permissions are confirmed (on macOS) or after onboarding completes.

View on GitHub (pinned to ba10ce1943)