From b02082d802b169e77715c449fe605f11fc7ddc6a Mon Sep 17 00:00:00 2001 From: Rabi Prasad Date: Tue, 21 Apr 2026 03:03:54 +0530 Subject: [PATCH] BZ-1810: fix: return 204 instead of 404 and 200 with error instead 401 for /prompt - The GET /api/public/v2/prompts/:name endpoint threw LangfuseNotFoundError (HTTP 404) when the prompt did not exist, which produced 4xx alert noise on ALB for benign client lookups. Return 204 No Content instead so clients can handle the absence without triggering infra alerts. - GET /api/public/v2/prompts/ now responds 200 with { accessDenied: true, message, prompt: null } on UnauthorizedError or ForbiddenError to quiet ALB 4xx alerts. Other errors still rethrow. --- .../server/handlers/promptNameHandler.ts | 29 +++-- .../project/[projectId]/juspay-dashboard.tsx | 108 +++++++++--------- 2 files changed, 72 insertions(+), 65 deletions(-) diff --git a/web/src/features/prompts/server/handlers/promptNameHandler.ts b/web/src/features/prompts/server/handlers/promptNameHandler.ts index a4b22c644ea1..eaa21fb70574 100644 --- a/web/src/features/prompts/server/handlers/promptNameHandler.ts +++ b/web/src/features/prompts/server/handlers/promptNameHandler.ts @@ -6,8 +6,9 @@ import { withMiddlewares } from "@/src/features/public-api/server/withMiddleware import { authorizePromptRequestOrThrow } from "../utils/authorizePromptRequest"; import { GetPromptByNameSchema, - LangfuseNotFoundError, PRODUCTION_LABEL, + UnauthorizedError, + ForbiddenError, } from "@langfuse/shared"; import { RateLimitService } from "@/src/features/public-api/server/RateLimitService"; import { auditLog } from "@/src/features/audit-logs/auditLog"; @@ -17,7 +18,20 @@ const getPromptNameHandler = async ( req: NextApiRequest, res: NextApiResponse, ) => { - const authCheck = await authorizePromptRequestOrThrow(req); + let authCheck: Awaited>; + try { + authCheck = await authorizePromptRequestOrThrow(req); + } catch (error) { + if (error instanceof UnauthorizedError || error instanceof ForbiddenError) { + res.status(200).json({ + accessDenied: true, + message: "You are not authorized to access this project", + prompt: null, + }); + return; + } + throw error; + } const rateLimitCheck = await RateLimitService.getInstance().rateLimitRequest( authCheck.scope, @@ -41,15 +55,8 @@ const getPromptNameHandler = async ( }); if (!prompt) { - let errorMessage = `Prompt not found: '${promptName}'`; - - if (version) { - errorMessage += ` with version ${version}`; - } else { - errorMessage += ` with label '${label ?? PRODUCTION_LABEL}'`; - } - - throw new LangfuseNotFoundError(errorMessage); + res.status(204).end(); + return; } res.status(200).json({ diff --git a/web/src/pages/project/[projectId]/juspay-dashboard.tsx b/web/src/pages/project/[projectId]/juspay-dashboard.tsx index a21fd034d629..a00a17ae070e 100644 --- a/web/src/pages/project/[projectId]/juspay-dashboard.tsx +++ b/web/src/pages/project/[projectId]/juspay-dashboard.tsx @@ -1683,7 +1683,7 @@ export default function JuspayDashboard() {
{/* Mobile Menu Button - Only show when sidebar is closed */} {isMobile && !isMobileMenuOpen && ( -
+
@@ -2057,7 +2057,7 @@ export default function JuspayDashboard() { {statistics.totalQueries} - + total
@@ -2066,7 +2066,7 @@ export default function JuspayDashboard() { ({statistics.correctPercentage}% - + correct)
@@ -2103,7 +2103,7 @@ export default function JuspayDashboard() { ? "9999+" : cardStatistics.merchantQueries} {showOnlyMerchant && ( -
+
)} @@ -2147,7 +2147,7 @@ export default function JuspayDashboard() { ? "9999+" : cardStatistics.geniusTeamQueries} {showOnlyTeam && ( -
+
)} @@ -2195,7 +2195,7 @@ export default function JuspayDashboard() { ? "9999+" : cardStatistics.juspayGeniusMerchantQueries} {showOnlyJuspayOthers && ( -
+
)} @@ -2224,7 +2224,7 @@ export default function JuspayDashboard() { )} >
- + - +

Advanced Filters @@ -2387,7 +2387,7 @@ export default function JuspayDashboard() { {/* Search Input */}
- + (