From c3f300e8ad715900814b8cde9adabe2c8fd92f3a Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 19 Mar 2026 09:06:37 +0000 Subject: [PATCH] Fix: surface build errors in deploy log instead of swallowing them When run_build() returned an Err (e.g. spawn failure because the build script path doesn't resolve) the error was only written to tracing, leaving the deploy log empty and the user with no clue. - build_worker now appends the Rust error message to the deploy log before setting status=failed, so it appears in the UI. - run_build logs CWD, resolved script path, exists=true/false, build dir, and env file path before attempting spawn, so there is always at least one diagnostic line in the log even if spawn itself fails. - spawn() error is wrapped with the attempted path for clarity. https://claude.ai/code/session_01FKCW3FDjNFj6jve4niMFXH --- server/src/builder.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/server/src/builder.rs b/server/src/builder.rs index c88e749..839d30d 100644 --- a/server/src/builder.rs +++ b/server/src/builder.rs @@ -45,6 +45,9 @@ pub async fn build_worker(state: AppState) { Some(id) => { if let Err(e) = run_build(&state, &id).await { tracing::error!("Build {} failed: {}", id, e); + // Surface the Rust-level error in the deploy log so it's visible in the UI. + let msg = format!("\n[hiy] FATAL: {}\n", e); + let _ = append_log(&state.db, &id, &msg).await; let _ = set_status(&state.db, &id, "failed").await; } } @@ -97,6 +100,24 @@ async fn run_build(state: &AppState, deploy_id: &str) -> anyhow::Result<()> { let build_dir = format!("{}/builds/{}", state.data_dir, app.id); + // Log diagnostics before spawning so even a spawn failure leaves a breadcrumb. + let cwd = std::env::current_dir() + .map(|p| p.display().to_string()) + .unwrap_or_else(|_| "".into()); + let script_exists = std::path::Path::new(&build_script).exists(); + append_log( + &state.db, + deploy_id, + &format!( + "[hiy] CWD: {}\n\ + [hiy] Build script: {} (exists={})\n\ + [hiy] Build dir: {}\n\ + [hiy] Env file: {}\n---\n", + cwd, build_script, script_exists, build_dir, env_file + ), + ) + .await?; + let mut child = Command::new("bash") .arg(&build_script) .env("APP_ID", &app.id) @@ -109,7 +130,8 @@ async fn run_build(state: &AppState, deploy_id: &str) -> anyhow::Result<()> { .env("BUILD_DIR", &build_dir) .stdout(std::process::Stdio::piped()) .stderr(std::process::Stdio::piped()) - .spawn()?; + .spawn() + .map_err(|e| anyhow::anyhow!("Failed to spawn '{}': {}", build_script, e))?; let stdout = child.stdout.take().expect("piped stdout"); let stderr = child.stderr.take().expect("piped stderr");