Skip to content

desktop: a pull request whose workflow failed to start disappears from the workspace view #9141

Closed as not planned

Description

@akshatcoder-hash

Steps to reproduce

  1. Open a workspace whose pull request has a check run with conclusion STARTUP_FAILURE (a workflow that cannot start) or STALE.
  2. Look at the workspace's pull request status.

Expected

The pull request shows with its checks, the way #8962 asks for the v2 path.

Actual

No pull request. The legacy desktop gh path validates each pull request with GHPRResponseSchema, and parsePRListResponse (apps/desktop/src/lib/trpc/routers/workspaces/utils/github/pr-resolution.ts:341-370) drops any item that fails validation — without a log for the list path.

Cause

The conclusion enum (apps/desktop/src/lib/trpc/routers/workspaces/utils/github/types.ts:9-21) lists 8 values and omits STARTUP_FAILURE and STALE, so safeParse fails for the whole pull request. parseChecks (pr-resolution.ts:417-451) and computeChecksStatus (:450-483) also lack STARTUP_FAILURE and would report it as pending once the schema accepts it.

Host-service has the same gap and it is being fixed separately: #8962, #8963. The mobile client and the v2 renderer already map STARTUP_FAILURE to failure.

Fix

Add both conclusions to the enum; map STARTUP_FAILURE to failure in parseChecks and computeChecksStatus. STALE stays pending, as in the host-service mapper.

Activity

  1. github-actions commented on Oct 30, 2026

    @github-actions
    Contributor

    The report holds up against the code.

    Summary

    In the legacy desktop gh path, if any check on a pull request finishes with STARTUP_FAILURE or STALE, the whole pull request disappears from the workspace view. The check-conclusion schema only accepts 8 values. One check with an unknown value fails validation for the entire PR object, and the list parser drops that PR without logging anything. Even after the schema accepts the new values, the two status mappers don't handle them correctly.

    Affected code

    • apps/desktop/src/lib/trpc/routers/workspaces/utils/github/types.ts:9-20: the GHCheckContextSchema.conclusion enum has SUCCESS, FAILURE, CANCELLED, SKIPPED, TIMED_OUT, ACTION_REQUIRED, NEUTRAL and "". STARTUP_FAILURE and STALE are missing.
    • apps/desktop/src/lib/trpc/routers/workspaces/utils/github/pr-resolution.ts:362-368: parsePRListResponse calls GHPRResponseSchema.safeParse(item) and only keeps items that pass. Failures are not logged. The single-PR path, parsePRResponse at :332-337, does log.
    • Both lookups use the list path, so both lose the PR:
      • findPRByHeadBranch (pr-resolution.ts:247)
      • findPRByHeadCommit (pr-resolution.ts:301)
    • pr-resolution.ts:417-448 (parseChecks): an unknown conclusion falls through to pending.
    • pr-resolution.ts:450-485 (computeChecksStatus): only PENDING, "", null and undefined count as pending. Anything else that isn't in the failure list counts as success.

    Root cause

    The root cause is the closed z.enum on conclusion in types.ts. Because statusCheckRollup is nested inside GHPRResponseSchema, one check with an unknown value fails safeParse for the whole PR. The silent continue in parsePRListResponse then hides the problem.

    One correction to the issue's proposed fix: it says "STALE stays pending". That is true in parseChecks, where the default branch returns pending. In computeChecksStatus it is not: STALE matches neither branch, so a PR whose only non-success check is STALE would get rollup "success". If the intent is pending, add STALE to the pending branch at :472-478.

    There is also a related mismatch. The host-service mapper (packages/host-service/src/runtime/pull-requests/utils/pull-request-mappers/pull-request-mappers.ts:165-168) maps ACTION_REQUIRED to failure. Desktop maps it to pending in parseChecks and to success in computeChecksStatus. It may be worth aligning while this code is open.

    Elsewhere, STARTUP_FAILURE is already handled in:

    • the v2 renderer: apps/desktop/src/renderer/routes/_authenticated/_dashboard/pull-requests/utils/toPullRequestDetail/toPullRequestDetail.ts:27
    • mobile: apps/mobile/screens/(authenticated)/workspace/[id]/utils/pullRequest/types.ts:30

    Reproduction

    Manual: open a workspace on a branch whose PR has a workflow that can't start, for example one with an invalid workflow YAML, which gives STARTUP_FAILURE. With the legacy (non-v2) desktop path, no PR is shown. Running gh pr list --head <branch> --json statusCheckRollup shows the STARTUP_FAILURE conclusion.

    bun:test sketch (pr-resolution.test.ts already imports computeChecksStatus):

    import { GHPRResponseSchema } from "./types";
    
    test("accepts STARTUP_FAILURE and STALE conclusions", () => {
    	for (const conclusion of ["STARTUP_FAILURE", "STALE"]) {
    		const result = GHPRResponseSchema.shape.statusCheckRollup.safeParse([
    			{ name: "ci", status: "COMPLETED", conclusion },
    		]);
    		expect(result.success).toBe(true);
    	}
    });
    
    test("STARTUP_FAILURE rolls up to failure", () => {
    	expect(
    		computeChecksStatus([{ name: "ci", conclusion: "STARTUP_FAILURE" }] as GHPRResponse["statusCheckRollup"]),
    	).toBe("failure");
    });
    
    test("STALE rolls up to pending", () => {
    	expect(
    		computeChecksStatus([{ name: "ci", conclusion: "STALE" }] as GHPRResponse["statusCheckRollup"]),
    	).toBe("pending");
    });

    (Adjust the statusCheckRollup access to match how GHPRResponseSchema is defined in types.ts.)

    Suggested fix

    1. Add "STARTUP_FAILURE" and "STALE" to the conclusion enum in types.ts. Optionally, also make it tolerant of future values, for example with a z.string() fallback, so a new GitHub conclusion can't hide a PR again.
    2. In parseChecks, map STARTUP_FAILURE to failure.
    3. In computeChecksStatus:
      • add STARTUP_FAILURE to the failure branch;
      • add STALE to the pending branch, because today it would count as success.
    4. Log validation failures in parsePRListResponse, as parsePRResponse already does, so the next schema drift is visible.
  2. Kitenite commented on Oct 31, 2026

    @Kitenite
    Member

    Closing: this is the v1 desktop path, which is being sunset. The v2 path maps STARTUP_FAILURE to failure (#8963, #9161).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions