BloopAI/vibe-kanban · critical · DeploymentError

Migration failed: {}

Error message

Migration failed: {}

What it means

LocalDeployment::new runs a one-time migration that moves execution process logs from the database to filesystem files. If migrate_execution_logs_to_files fails, deployment initialization aborts with 'Migration failed: {e}'. Since it runs at startup, a failure here prevents the whole local deployment from starting.

Source

Thrown at crates/local-deployment/src/lib.rs:96

    webrtc_host: OnceLock<Arc<WebRtcHost>>,
    ssh_config: Arc<russh::server::Config>,
    pty: PtyService,
    pr_sync_notify: Arc<Notify>,
}

#[derive(Debug, Clone)]
struct PendingHandoff {
    provider: String,
    app_verifier: String,
}

#[async_trait]
impl Deployment for LocalDeployment {
    async fn new(shutdown: CancellationToken) -> Result<Self, DeploymentError> {
        // Run one-time process logs migration from DB to filesystem
        services::services::execution_process::migrate_execution_logs_to_files()
            .await
            .map_err(|e| DeploymentError::Other(anyhow::anyhow!("Migration failed: {}", e)))?;

        let mut raw_config = load_config_from_file(&config_path()).await;

        let profiles = ExecutorConfigs::get_cached();
        if !raw_config.onboarding_acknowledged
            && let Ok(recommended_executor) = profiles.get_recommended_executor_profile().await
        {
            raw_config.executor_profile = recommended_executor;
        }

        // Check if app version has changed and set release notes flag
        {
            let current_version = utils::version::APP_VERSION;
            let stored_version = raw_config.last_app_version.as_deref();

            if stored_version != Some(current_version) {
                // Show release notes only if this is an upgrade (not first install)
                raw_config.show_release_notes = stored_version.is_some();

View on GitHub (pinned to 4deb7eca8f)

Solutions

  1. Read the wrapped '{e}' message to identify whether it is a DB error or a filesystem write error, and fix that root cause.
  2. Check the log storage directory exists and is writable by the process user (mkdir/chown as needed).
  3. Free disk space if the write failed due to quota/disk-full.
  4. Restore DB connectivity (check DATABASE_URL / sqlite file) and restart the deployment; the migration is one-time and will re-run.

Example fix

// before (diagnostic)
migrate_execution_logs_to_files().await.map_err(|e| ...)?;
// after: pre-flight check
services::services::execution_process::migrate_execution_logs_to_files()
    .await
    .inspect_err(|e| tracing::error!(?e, "log migration failed; check log dir permissions and disk space"))
    .map_err(|e| DeploymentError::Other(anyhow::anyhow!("Migration failed: {}", e)))?;
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight before deployment init
let log_dir = logs_base_dir();
if !log_dir.exists() {
    std::fs::create_dir_all(&log_dir)?;
}
let probe = log_dir.join(".write-probe");
std::fs::write(&probe, b"ok")?;
std::fs::remove_file(&probe)?;

Try / catch

match LocalDeployment::new(shutdown).await {
    Err(DeploymentError::Other(e)) if e.to_string().starts_with("Migration failed") => {
        tracing::error!(%e, "fix log dir permissions/DB, then restart deployment");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Starting the local deployment when the log migration cannot complete: DB read failures on execution_process rows, unwritable log directory, disk full, or partial prior migration state causing conflicts.

Common situations: Read-only or permission-denied log directory (e.g. after changing CODE_HOME or running under a different user); corrupted DB rows with oversized/binary log content; interrupted previous migration leaving half-written files; disk quota exceeded.

Related errors


AI-assisted analysis of BloopAI/vibe-kanban@4deb7eca8f (2026-08-29). Data as JSON: /api/errors/31cbf96402bf3ada. Report an issue: GitHub.