Return 404 for missing CI runs instead of 500
query_row returns QueryReturnedNoRows when no row matches, which was
being treated as a generic DB error. Added is_no_rows helper to
distinguish not-found from real failures and return the proper status
code. Updated the codified-bug test to assert 404.

Assisted-by: GLM-5.1 via pi
change otylxppvswuruzxruturtrtsopuszprz
commit 81a845cb898396fdb5f27f1190596a4b3fa871df
author Alpha Chen <alpha@kejadlen.dev>
date
parent vnmlqxkw
diff --git a/src/quire/web/handlers.rs b/src/quire/web/handlers.rs
index 9a580a9..62c18d8 100644
--- a/src/quire/web/handlers.rs
+++ b/src/quire/web/handlers.rs
@@ -34,6 +34,14 @@ pub async fn stylesheet() -> Response {
         .into_response()
 }
 
+/// True when the error is "query returned no rows" (i.e. resource not found).
+fn is_no_rows(err: &crate::error::Error) -> bool {
+    matches!(
+        err,
+        crate::error::Error::Sql(rusqlite::Error::QueryReturnedNoRows)
+    )
+}
+
 /// Read a CRI log file, returning empty on NotFound and on any other
 /// error after logging it.
 async fn read_log(path: &std::path::Path) -> String {
@@ -119,6 +127,7 @@ pub async fn run_detail(
     let result = db::load_run_detail(&quire, &repo_name, &run_id);
     let detail = match result {
         Ok(d) => d,
+        Err(ref e) if is_no_rows(e) => return StatusCode::NOT_FOUND.into_response(),
         Err(e) => {
             tracing::error!(repo = %repo, run_id = %run_id, error = %display_chain(&e), "failed to load run detail");
             return render_error(
@@ -378,18 +387,15 @@ mod tests {
     }
 
     #[tokio::test]
-    async fn run_detail_returns_empty_for_unknown_repo() {
+    async fn run_detail_returns_404_for_missing_run() {
         let env = TestEnv::new();
         let app = env.app();
-        // Valid UUID but repo has no runs — the DB query returns no row,
-        // which triggers a 500 "failed to load run detail".
-        // This tests the full pipeline with a real DB.
+        // Valid UUID but no run exists — should return 404, not 500.
         let req = Request::builder()
             .uri(&format!("/example/ci/{UUID1}"))
             .body(Body::empty())
             .unwrap();
         let resp = app.oneshot(req).await.unwrap();
-        // No run inserted, so query_row returns Err.
-        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
+        assert_eq!(resp.status(), StatusCode::NOT_FOUND);
     }
 }