Skip to content

fix(host-service): classify expected GitHub auth and 404 outcomes as non-500s - #6389

Merged
saddlepaddle merged 1 commit into
mainfrom
sentry/hs-github-expected-outcomes
Aug 12, 2026
Merged

saddlepaddle merged 1 commit into
mainfrom
sentry/hs-github-expected-outcomes

Conversation

@saddlepaddle

@saddlepaddle saddlepaddle commented Aug 12, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

Two expected GitHub outcomes escape host-service tRPC procedures as INTERNAL_SERVER_ERROR 500s and file Sentry issues:

  • HOST-SERVICE-1M (6 events, 1.20.2): when a user has no GitHub credentials configured, the shared github() context factory throws a plain Error("No GitHub token available...") the moment any procedure requests an Octokit client (seen on git.getPullRequestThreads). Every PR view without GitHub auth files a 500.
  • HOST-SERVICE-1Q (2 events, 1.20.2): in workspaceCreation.searchPullRequests, an explicit-PR-number lookup for a PR that doesn't exist or isn't accessible rejects with an Octokit HttpError 404 that propagates unclassified.

Root cause

Both are expected domain states (missing precondition / empty result) thrown as untyped errors, so the tRPC Sentry middleware — which reports anything still INTERNAL_SERVER_ERROR at the boundary — correctly treats them as bugs. Per the repo's error contract, the missing translation belongs at the throw sites, never as a Sentry-side filter.

Fix

  • packages/host-service/src/app.ts: the github() context factory now throws TRPCError({ code: "PRECONDITION_FAILED", cause: { kind: "NO_GITHUB_TOKEN" } }) with the existing message unchanged. Every procedure that calls ctx.github() inherits the classification from this one shared site; no call sites touched.
  • packages/host-service/src/trpc/router/workspace-creation/procedures/search-pull-requests.ts: octokitDirectLookupRow treats a 404 from octokit.pulls.get as "no matching PR" and returns null, which the single-target caller already handles gracefully (emptyPullRequestsPage) and which matches how the multi-target Promise.allSettled path already filters 404 rejections via isGithubNotFoundError (status/name check, no instanceof).

Genuine unexpected GitHub failures (5xx, network, rate limits) still propagate and report exactly as before. github.mergePR classification (HOST-SERVICE-1P) is intentionally untouched — open PR #6228 owns github.ts.

Verification

bunx biome check on the two changed files:

Checked 2 files in 12ms. No fixes applied.

cd packages/host-service && bun run typecheck:

$ tsc --noEmit --emitDeclarationOnly false
typecheck exit=0

No existing tests cover the changed code paths (no co-located test files for app.ts or search-pull-requests.ts), so no test run applies.

Refs HOST-SERVICE-1M
Refs HOST-SERVICE-1Q

https://claude.ai/code/session_72e9200a-ff85-4667-ac6d-add2c90fb109


Summary by cubic

Classifies two expected GitHub outcomes so they no longer surface as 500s or file Sentry issues. Previously, missing GitHub credentials or a direct PR lookup 404 resulted in INTERNAL_SERVER_ERROR; now missing credentials throw PRECONDITION_FAILED and 404 direct lookups return null (empty result). Unexpected GitHub failures still propagate unchanged.

What changed

  • packages/host-service/src/app.ts: github() now throws TRPCError (PRECONDITION_FAILED, cause { kind: "NO_GITHUB_TOKEN" }) from @trpc/server instead of a generic error.
  • packages/host-service/src/trpc/router/workspace-creation/procedures/search-pull-requests.ts: treat @octokit/rest pulls.get 404 as “no matching PR” and return null via existing isGithubNotFoundError; caller already handles empty results. No call sites changed.
  • Client-visible behavior: missing GitHub auth is now a PRECONDITION_FAILED tRPC error; single-PR direct lookup may return null instead of throwing. Sentry noise is reduced; github.mergePR handling is unchanged.

Written for commit c928b75. Summary will update on new commits.

Review in cubic

@coderabbitai

coderabbitai Bot commented Aug 12, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The host service now reports missing GitHub credentials with a typed tRPC error. Direct pull-request lookups return null for missing or inaccessible pull requests and preserve other errors.

Changes

GitHub error handling

Layer / File(s) Summary
Credential error classification
packages/host-service/src/app.ts
The GitHub client factory now throws PRECONDITION_FAILED with the NO_GITHUB_TOKEN cause when credentials are missing.
Pull-request lookup fallback
packages/host-service/src/trpc/router/workspace-creation/procedures/search-pull-requests.ts
The lookup returns null for GitHub 404 responses, rethrows other errors, and documents the unavailable pull-request outcome.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested reviewers: kitenite

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title uses conventional commit format and clearly summarizes the GitHub authentication and 404 error classification changes.
Description check ✅ Passed The description explains the problem, root cause, fix, testing, and scope, although it does not reproduce the repository checklist.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sentry/hs-github-expected-outcomes

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 12, 2026 •

Copy link
Copy Markdown
Contributor

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch

Thank you for your contribution! 🎉

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/host-service/src/app.ts (1)

101-106: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add regression coverage for the typed tRPC error contract.

Test that a missing token produces PRECONDITION_FAILED with cause.kind === "NO_GITHUB_TOKEN". Also test that a valid token still creates an authenticated Octokit client.

The PR objectives state that no existing tests cover the changed paths.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/host-service/src/app.ts` around lines 101 - 106, Add regression
tests for the missing-token and valid-token branches in the application’s GitHub
client setup: assert that the missing-token path throws TRPCError code
PRECONDITION_FAILED with cause.kind equal to NO_GITHUB_TOKEN, and that providing
a valid token creates an authenticated Octokit client. Use the existing app
setup and test utilities rather than changing the error contract.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@packages/host-service/src/trpc/router/workspace-creation/procedures/search-pull-requests.ts`:
- Around line 416-429: Update the Octokit catch in the pull-request fetch flow
to return null only when the error’s HTTP status is exactly 404, allowing other
failures—including messages containing “not found”—to propagate. Keep
isGithubNotFoundError unchanged for execGh results, and add a regression test
covering a non-404 error with a “not found” message.

---

Nitpick comments:
In `@packages/host-service/src/app.ts`:
- Around line 101-106: Add regression tests for the missing-token and
valid-token branches in the application’s GitHub client setup: assert that the
missing-token path throws TRPCError code PRECONDITION_FAILED with cause.kind
equal to NO_GITHUB_TOKEN, and that providing a valid token creates an
authenticated Octokit client. Use the existing app setup and test utilities
rather than changing the error contract.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6b6a627b-2b8b-4de7-ae0c-98e022eba2de

📥 Commits

Reviewing files that changed from the base of the PR and between b671c27 and c928b75.

📒 Files selected for processing (2)
  • packages/host-service/src/app.ts
  • packages/host-service/src/trpc/router/workspace-creation/procedures/search-pull-requests.ts

Comment on lines +416 to +429
const response = await octokit.pulls
.get({
owner: repo.owner,
repo: repo.name,
pull_number: prNumber,
})
.catch((error: unknown) => {
// A 404 means the PR doesn't exist or isn't accessible to the user —
// an expected empty result, not an internal error.
if (isGithubNotFoundError(error)) return null;
throw error;
});
if (!response) return null;
const pr = response.data;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- target procedure ---'
sed -n '380,445p' packages/host-service/src/trpc/router/workspace-creation/procedures/search-pull-requests.ts
printf '%s\n' '--- helper definition and usages ---'
rg -n -C 8 'isGithubNotFoundError' packages/host-service/src
printf '%s\n' '--- relevant tests ---'
rg -n -C 6 'search-pull|pull.?request|not found|HTTP 404|status.*404' packages/host-service --glob '*.{test,spec}.{ts,tsx,js,jsx}'

Repository: superset-sh/superset

Length of output: 50376


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- helper implementation ---'
sed -n '145,210p' packages/host-service/src/trpc/router/workspace-creation/shared/github-search.ts
printf '%s\n' '--- focused helper tests ---'
sed -n '218,245p' packages/host-service/src/trpc/router/workspace-creation/shared/github-search.test.ts
printf '%s\n' '--- behavior probe ---'
node - <<'JS'
const pattern = /could not resolve to|\bnot found\b|HTTP 404/i;
const errors = [
  Object.assign(new Error("Not Found"), { status: 404 }),
  Object.assign(new Error("Not Found"), { status: 500 }),
  Object.assign(new Error("transport: resource not found"), { status: 503 }),
  Object.assign(new Error("rate limit exceeded"), { status: 429 }),
];
for (const error of errors) {
  const status =
    typeof error === "object" && error !== null && "status" in error
      ? error.status
      : undefined;
  console.log(JSON.stringify({
    message: error.message,
    status,
    sharedPredicate: status === 404 || pattern.test(error.message),
    statusOnlyPredicate: status === 404,
  }));
}
JS

Repository: superset-sh/superset

Length of output: 3369


Restrict the fallback to an actual 404 response.

At line 425, check the Octokit error status directly. A non-404 error with not found in its message currently returns null and hides the failure. Keep isGithubNotFoundError for execGh results. Add a regression test for this case.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/host-service/src/trpc/router/workspace-creation/procedures/search-pull-requests.ts`
around lines 416 - 429, Update the Octokit catch in the pull-request fetch flow
to return null only when the error’s HTTP status is exactly 404, allowing other
failures—including messages containing “not found”—to propagate. Keep
isGithubNotFoundError unchanged for execGh results, and add a regression test
covering a non-404 error with a “not found” message.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 2 files

You’re at about 99% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

Architecture diagram
sequenceDiagram
    participant Client as tRPC Client
    participant TRPC as tRPC Procedure
    participant GH as github() Context Factory
    participant Octokit as Octokit Client
    participant Sentry as Sentry Middleware

    Note over Client,Sentry: GitHub Auth Flow (every ctx.github() procedure)
    
    Client->>TRPC: Invoke tRPC procedure (e.g., git.getPullRequestThreads)
    TRPC->>GH: Request GitHub context
    GH->>GH: Get token from credential providers
    
    alt Token available
        GH-->>TRPC: Octokit client
        TRPC->>Octokit: GitHub API call
        Octokit-->>TRPC: Response
    else No token configured
        GH-->>TRPC: TRPCError PRECONDITION_FAILED (cause: NO_GITHUB_TOKEN)
        Note over GH,TRPC: Classified as precondition failure - not 500
        TRPC->>Sentry: PRECONDITION_FAILED error
        Sentry-->>Client: Non-500 error (no Sentry alert)
    end

    Note over Client,Sentry: PR Direct Lookup Flow (searchPullRequests)
    
    Client->>TRPC: searchPullRequests(single PR number)
    TRPC->>Octokit: octokit.pulls.get()
    
    alt PR found
        Octokit-->>TRPC: Pull request data
        TRPC->>TRPC: Apply author/review filters
        TRPC-->>Client: PullRequestResult
    else PR not found (404)
        Octokit-->>TRPC: HttpError 404
        TRPC->>TRPC: Check via isGithubNotFoundError
        TRPC-->>Client: null (empty result)
        Note over TRPC,Sentry: 404 treated as expected empty result - not 500
    else Other error (5xx, network, rate limit)
        Octokit-->>TRPC: Other error
        TRPC->>Sentry: Propagate as INTERNAL_SERVER_ERROR
        Sentry-->>Client: 500 + Sentry alert
    end
Loading

Re-trigger cubic

@saddlepaddle
saddlepaddle merged commit bcd18de into main Aug 12, 2026
18 of 19 checks passed
@saddlepaddle
saddlepaddle deleted the sentry/hs-github-expected-outcomes branch August 12, 2026 17:48

This branch was previously deployed

1 inactive deployment
preview — c928b752 Deployed Aug 12, 2026 by saddlepaddle via Deploy Marketing #7527
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant