Skip to content

Commit 15b1eb8

Browse files
committed
fix(webapp): stop leaking exception messages on 5xx API responses
Across the webapp API routes, the catch-all 500 branch surfaced raw `error.message` verbatim. When the underlying exception originated from an internal subsystem, this leaked server-side details into customer-visible responses. Replace each leaking branch with a generic body and route the full error through logger.error so visibility is preserved server-side. 4xx branches that intentionally surface user-facing messages (e.g. ServiceValidationError) are left intact.
1 parent 3e6458f commit 15b1eb8

20 files changed

Lines changed: 64 additions & 70 deletions
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
area: webapp
3+
type: fix
4+
---
5+
6+
Stop leaking raw exception messages on 500 responses across webapp API routes; return a generic error string and log the full error server-side instead.

apps/webapp/app/routes/admin.api.v1.platform-notifications.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { type ActionFunctionArgs, json } from "@remix-run/server-runtime";
22
import { err, ok, type Result } from "neverthrow";
3+
import { logger } from "~/services/logger.server";
34
import { authenticateAdminRequest } from "~/services/personalAccessToken.server";
45
import {
56
createPlatformNotification,
@@ -42,7 +43,8 @@ export async function action({ request }: ActionFunctionArgs) {
4243
return json({ error: "Validation failed", details: error.issues }, { status: 400 });
4344
}
4445

45-
return json({ error: error.message }, { status: 500 });
46+
logger.error("Failed to create platform notification", { error });
47+
return json({ error: "Something went wrong" }, { status: 500 });
4648
}
4749

4850
return json(result.value, { status: 201 });

apps/webapp/app/routes/admin.notifications.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import {
3737
TableRow,
3838
} from "~/components/primitives/Table";
3939
import { prisma } from "~/db.server";
40+
import { logger } from "~/services/logger.server";
4041
import { requireUserId } from "~/services/session.server";
4142
import {
4243
archivePlatformNotification,
@@ -234,7 +235,8 @@ async function handleCreateAction(formData: FormData, userId: string, isPreview:
234235
{ status: 400 }
235236
);
236237
}
237-
return typedjson({ error: err.message }, { status: 500 });
238+
logger.error("Failed to create platform notification", { error: err });
239+
return typedjson({ error: "Something went wrong" }, { status: 500 });
238240
}
239241

240242
if (isPreview) {
@@ -310,7 +312,8 @@ async function handleEditAction(formData: FormData) {
310312
{ status: 400 }
311313
);
312314
}
313-
return typedjson({ error: err.message }, { status: 500 });
315+
logger.error("Failed to update platform notification", { error: err });
316+
return typedjson({ error: "Something went wrong" }, { status: 500 });
314317
}
315318

316319
return typedjson({ success: true, id: result.value.id });

apps/webapp/app/routes/api.v1.batches.$batchParam.results.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { z } from "zod";
44
import { ApiBatchResultsPresenter } from "~/presenters/v3/ApiBatchResultsPresenter.server";
55
import { ApiRunResultPresenter } from "~/presenters/v3/ApiRunResultPresenter.server";
66
import { authenticateApiRequest } from "~/services/apiAuth.server";
7+
import { logger } from "~/services/logger.server";
78

89
const ParamsSchema = z.object({
910
/* This is the batch friendly ID */
@@ -36,10 +37,7 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
3637

3738
return json(result);
3839
} catch (error) {
39-
if (error instanceof Error) {
40-
return json({ error: error.message }, { status: 500 });
41-
} else {
42-
return json({ error: JSON.stringify(error) }, { status: 500 });
43-
}
40+
logger.error("Failed to load batch results", { error });
41+
return json({ error: "Something went wrong" }, { status: 500 });
4442
}
4543
}

apps/webapp/app/routes/api.v1.deployments.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,10 @@ export async function action({ request, params }: ActionFunctionArgs) {
5555
} catch (error) {
5656
if (error instanceof ServiceValidationError) {
5757
return json({ error: error.message }, { status: 400 });
58-
} else if (error instanceof Error) {
59-
logger.error("Error initializing deployment", { error: error.message });
60-
return json({ error: `Internal server error: ${error.message}` }, { status: 500 });
61-
} else {
62-
logger.error("Error initializing deployment", { error: String(error) });
63-
return json({ error: "Internal server error" }, { status: 500 });
6458
}
59+
60+
logger.error("Error initializing deployment", { error });
61+
return json({ error: "Internal server error" }, { status: 500 });
6562
}
6663
}
6764

apps/webapp/app/routes/api.v1.projects.$projectRef.alertChannels.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
ApiAlertChannelPresenter,
66
ApiCreateAlertChannel,
77
} from "~/presenters/v3/ApiAlertChannelPresenter.server";
8+
import { logger } from "~/services/logger.server";
89
import { authenticateApiRequestWithPersonalAccessToken } from "~/services/personalAccessToken.server";
910
import { CreateAlertChannelService } from "~/v3/services/alerts/createAlertChannel.server";
1011
import { ServiceValidationError } from "~/v3/services/baseService.server";
@@ -88,9 +89,7 @@ export async function action({ request, params }: ActionFunctionArgs) {
8889
return json({ error: error.message }, { status: 422 });
8990
}
9091

91-
return json(
92-
{ error: error instanceof Error ? error.message : "Internal Server Error" },
93-
{ status: 500 }
94-
);
92+
logger.error("Failed to create alert channel", { error });
93+
return json({ error: "Something went wrong" }, { status: 500 });
9594
}
9695
}

apps/webapp/app/routes/api.v1.queues.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { json } from "@remix-run/server-runtime";
22
import { type QueueItem } from "@trigger.dev/core/v3";
33
import { z } from "zod";
44
import { QueueListPresenter } from "~/presenters/v3/QueueListPresenter.server";
5+
import { logger } from "~/services/logger.server";
56
import { createLoaderApiRoute } from "~/services/routeBuilders/apiBuilder.server";
67
import { ServiceValidationError } from "~/v3/services/baseService.server";
78

@@ -35,10 +36,8 @@ export const loader = createLoaderApiRoute(
3536
return json({ error: error.message }, { status: 422 });
3637
}
3738

38-
return json(
39-
{ error: error instanceof Error ? error.message : "Internal Server Error" },
40-
{ status: 500 }
41-
);
39+
logger.error("Failed to list queues", { error });
40+
return json({ error: "Something went wrong" }, { status: 500 });
4241
}
4342
}
4443
);

apps/webapp/app/routes/api.v1.runs.$runFriendlyId.input-streams.wait.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
deleteInputStreamWaitpoint,
1212
setInputStreamWaitpoint,
1313
} from "~/services/inputStreamWaitpointCache.server";
14+
import { logger } from "~/services/logger.server";
1415
import { getRealtimeStreamInstance } from "~/services/realtime/v1StreamsGlobal.server";
1516
import { createActionApiRoute } from "~/services/routeBuilders/apiBuilder.server";
1617
import { parseDelay } from "~/utils/delays";
@@ -138,10 +139,9 @@ const { action, loader } = createActionApiRoute(
138139
} catch (error) {
139140
if (error instanceof ServiceValidationError) {
140141
return json({ error: error.message }, { status: 422 });
141-
} else if (error instanceof Error) {
142-
return json({ error: error.message }, { status: 500 });
143142
}
144143

144+
logger.error("Failed to create input-stream waitpoint", { error });
145145
return json({ error: "Something went wrong" }, { status: 500 });
146146
}
147147
}

apps/webapp/app/routes/api.v1.runs.$runId.tags.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { z } from "zod";
44
import { prisma } from "~/db.server";
55
import { MAX_TAGS_PER_RUN } from "~/models/taskRunTag.server";
66
import { authenticateApiRequest } from "~/services/apiAuth.server";
7+
import { logger } from "~/services/logger.server";
78

89
const ParamsSchema = z.object({
910
runId: z.string(),
@@ -85,9 +86,7 @@ export async function action({ request, params }: ActionFunctionArgs) {
8586

8687
return json({ message: `Successfully set ${newTags.length} new tags.` }, { status: 200 });
8788
} catch (error) {
88-
return json(
89-
{ error: error instanceof Error ? error.message : "Internal Server Error" },
90-
{ status: 500 }
91-
);
89+
logger.error("Failed to add run tags", { error });
90+
return json({ error: "Something went wrong" }, { status: 500 });
9291
}
9392
}

apps/webapp/app/routes/api.v1.runs.$runParam.attempts.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { ActionFunctionArgs } from "@remix-run/server-runtime";
22
import { json } from "@remix-run/server-runtime";
33
import { z } from "zod";
44
import { authenticateApiRequest } from "~/services/apiAuth.server";
5+
import { logger } from "~/services/logger.server";
56
import { ServiceValidationError } from "~/v3/services/baseService.server";
67
import { CreateTaskRunAttemptService } from "~/v3/services/createTaskRunAttempt.server";
78

@@ -40,9 +41,7 @@ export async function action({ request, params }: ActionFunctionArgs) {
4041
return json({ error: error.message }, { status: error.status ?? 422 });
4142
}
4243

43-
return json(
44-
{ error: error instanceof Error ? error.message : "Internal Server Error" },
45-
{ status: 500 }
46-
);
44+
logger.error("Failed to create run attempt", { error });
45+
return json({ error: "Something went wrong" }, { status: 500 });
4746
}
4847
}

0 commit comments

Comments
 (0)