From c9ee8e7a7e1ec12022897333d0154a06cf1dd4c4 Mon Sep 17 00:00:00 2001 From: plind-dm <59729252+plind-dm@users.noreply.github.com> Date: Fri, 3 Apr 2026 09:56:23 +0900 Subject: [PATCH] fix(issues): replace non-null assertions with null checks in checkout re-read Two code paths in issueService.checkout() used rows[0]! when re-reading an issue after stale-run adoption or self-ownership verification. If the issue is deleted concurrently (company cascade, API delete), rows[0] is undefined and withIssueLabels crashes with an unhandled TypeError. Replace both with rows[0] ?? null and throw notFound when the row is missing, returning a clean 404 instead of an uncaught exception. --- server/src/services/issues.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/server/src/services/issues.ts b/server/src/services/issues.ts index 832c4e17..3e1b2eb2 100644 --- a/server/src/services/issues.ts +++ b/server/src/services/issues.ts @@ -1469,7 +1469,8 @@ export function issueService(db: Db) { expectedCheckoutRunId: current.checkoutRunId, }); if (adopted) { - const row = await db.select().from(issues).where(eq(issues.id, id)).then((rows) => rows[0]!); + const row = await db.select().from(issues).where(eq(issues.id, id)).then((rows) => rows[0] ?? null); + if (!row) throw notFound("Issue not found"); const [enriched] = await withIssueLabels(db, [row]); return enriched; } @@ -1481,7 +1482,8 @@ export function issueService(db: Db) { current.status === "in_progress" && sameRunLock(current.checkoutRunId, checkoutRunId) ) { - const row = await db.select().from(issues).where(eq(issues.id, id)).then((rows) => rows[0]!); + const row = await db.select().from(issues).where(eq(issues.id, id)).then((rows) => rows[0] ?? null); + if (!row) throw notFound("Issue not found"); const [enriched] = await withIssueLabels(db, [row]); return enriched; }