diff --git a/packages/backend/src/api.ts b/packages/backend/src/api.ts
index 3be070349..33f854ada 100644
--- a/packages/backend/src/api.ts
+++ b/packages/backend/src/api.ts
@@ -9,6 +9,7 @@ import { AccountPermissionSyncer } from './ee/accountPermissionSyncer.js';
import { PromClient } from './promClient.js';
import { RepoIndexManager } from './repoIndexManager.js';
import { createGitHubRepoRecord } from './repoCompileUtils.js';
+import { isNotFound } from './errors.js';
import { Octokit } from '@octokit/rest';
import { SINGLE_TENANT_ORG_ID } from './constants.js';
import z from 'zod';
@@ -150,10 +151,19 @@ export class Api {
}
const octokit = new Octokit();
- const response = await octokit.rest.repos.get({
- owner: parsed.data.owner,
- repo: parsed.data.repo,
- });
+ let response;
+ try {
+ response = await octokit.rest.repos.get({
+ owner: parsed.data.owner,
+ repo: parsed.data.repo,
+ });
+ } catch (error) {
+ if (isNotFound(error)) {
+ res.status(404).json({ error: 'Repository not found on GitHub' });
+ return;
+ }
+ throw error;
+ }
const record = createGitHubRepoRecord({
repo: response.data,
diff --git a/packages/backend/src/errors.ts b/packages/backend/src/errors.ts
index d14760a49..e174f0b20 100644
--- a/packages/backend/src/errors.ts
+++ b/packages/backend/src/errors.ts
@@ -27,4 +27,5 @@ const getStatus = (err: unknown): number | null => {
export const isUnauthorized = (err: unknown): boolean => getStatus(err) === 401;
export const isForbidden = (err: unknown): boolean => getStatus(err) === 403;
+export const isNotFound = (err: unknown): boolean => getStatus(err) === 404;
export const isGone = (err: unknown): boolean => getStatus(err) === 410;
diff --git a/packages/web/src/app/(app)/askgh/[owner]/[repo]/components/repoNotFound.tsx b/packages/web/src/app/(app)/askgh/[owner]/[repo]/components/repoNotFound.tsx
new file mode 100644
index 000000000..070afa371
--- /dev/null
+++ b/packages/web/src/app/(app)/askgh/[owner]/[repo]/components/repoNotFound.tsx
@@ -0,0 +1,31 @@
+import { FileQuestion } from "lucide-react";
+import Link from "next/link";
+import { buttonVariants } from "@/components/ui/button";
+import { cn } from "@/lib/utils";
+
+interface Props {
+ owner: string;
+ repo: string;
+}
+
+export function RepoNotFound({ owner, repo }: Props) {
+ return (
+
+
+
+ Repository not found
+
+
+ We couldn't find{" "}
+ {owner}/{repo}{" "}
+ on GitHub. It may not exist, or it might be private.
+
+
+ Go back home
+
+
+ );
+}
diff --git a/packages/web/src/app/(app)/askgh/[owner]/[repo]/page.tsx b/packages/web/src/app/(app)/askgh/[owner]/[repo]/page.tsx
index 37e49ce5a..caee69b70 100644
--- a/packages/web/src/app/(app)/askgh/[owner]/[repo]/page.tsx
+++ b/packages/web/src/app/(app)/askgh/[owner]/[repo]/page.tsx
@@ -1,10 +1,12 @@
import { addGithubRepo } from "@/features/workerApi/actions";
import { isServiceError } from "@/lib/utils";
-import { ServiceErrorException } from "@/lib/serviceError";
+import { ServiceError, ServiceErrorException } from "@/lib/serviceError";
+import { ErrorCode } from "@/lib/errorCodes";
import { __unsafePrisma } from "@/prisma";
import { getRepoInfo } from "./api";
import { CustomSlateEditor } from "@/features/chat/customSlateEditor";
import { RepoIndexedGuard } from "./components/repoIndexedGuard";
+import { RepoNotFound } from "./components/repoNotFound";
import { LandingPage } from "./components/landingPage";
import { getConfiguredLanguageModelsInfo } from "@/features/chat/utils.server";
import { auth } from "@/auth";
@@ -27,7 +29,7 @@ export default async function GitHubRepoPage(props: PageProps) {
return ;
}
- const repoId = await (async () => {
+ const repoIdOrError = await (async (): Promise => {
// 1. Look up repo by owner/repo
const displayName = `${owner}/${repo}`;
const existingRepo = await __unsafePrisma.repo.findFirst({
@@ -46,12 +48,22 @@ export default async function GitHubRepoPage(props: PageProps) {
const response = await addGithubRepo(owner, repo);
if (isServiceError(response)) {
- throw new ServiceErrorException(response);
+ return response;
}
return response.repoId;
})();
+ if (isServiceError(repoIdOrError)) {
+ if (repoIdOrError.errorCode === ErrorCode.REPOSITORY_NOT_FOUND) {
+ return ;
+ }
+
+ throw new ServiceErrorException(repoIdOrError);
+ }
+
+ const repoId = repoIdOrError;
+
const repoInfo = await getRepoInfo(repoId)
const languageModels = await getConfiguredLanguageModelsInfo()
diff --git a/packages/web/src/features/workerApi/actions.ts b/packages/web/src/features/workerApi/actions.ts
index 9e681d9de..e040ea1e0 100644
--- a/packages/web/src/features/workerApi/actions.ts
+++ b/packages/web/src/features/workerApi/actions.ts
@@ -1,7 +1,7 @@
'use server';
import { sew } from "@/middleware/sew";
-import { unexpectedError } from "@/lib/serviceError";
+import { repositoryNotFound, unexpectedError } from "@/lib/serviceError";
import { withAuth, withOptionalAuth } from "@/middleware/withAuth";
import { withMinimumOrgRole } from "@/middleware/withMinimumOrgRole";
import { OrgRole } from "@sourcebot/db";
@@ -95,6 +95,9 @@ export const addGithubRepo = async (owner: string, repo: string) => sew(() =>
});
if (!response.ok) {
+ if (response.status === 404) {
+ return repositoryNotFound(`${owner}/${repo}`);
+ }
return unexpectedError('Failed to add GitHub repo');
}
diff --git a/packages/web/src/lib/serviceError.ts b/packages/web/src/lib/serviceError.ts
index f2b447ced..d0b789f1d 100644
--- a/packages/web/src/lib/serviceError.ts
+++ b/packages/web/src/lib/serviceError.ts
@@ -103,6 +103,14 @@ export const notFound = (message?: string): ServiceError => {
}
}
+export const repositoryNotFound = (repository: string): ServiceError => {
+ return {
+ statusCode: StatusCodes.NOT_FOUND,
+ errorCode: ErrorCode.REPOSITORY_NOT_FOUND,
+ message: `Repository "${repository}" was not found`,
+ }
+}
+
export const userNotFound = (): ServiceError => {
return {
statusCode: StatusCodes.NOT_FOUND,