Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .server-changes/sanitize-api-500-errors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
area: webapp
type: fix
---

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.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { type ActionFunctionArgs, json } from "@remix-run/server-runtime";
import { err, ok, type Result } from "neverthrow";
import { logger } from "~/services/logger.server";
import { authenticateAdminRequest } from "~/services/personalAccessToken.server";
import {
createPlatformNotification,
Expand Down Expand Up @@ -42,7 +43,8 @@ export async function action({ request }: ActionFunctionArgs) {
return json({ error: "Validation failed", details: error.issues }, { status: 400 });
}

return json({ error: error.message }, { status: 500 });
logger.error("Failed to create platform notification", { error });
return json({ error: "Something went wrong" }, { status: 500 });
}

return json(result.value, { status: 201 });
Expand Down
34 changes: 26 additions & 8 deletions apps/webapp/app/routes/admin.notifications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
TableRow,
} from "~/components/primitives/Table";
import { prisma } from "~/db.server";
import { logger } from "~/services/logger.server";
import { requireUserId } from "~/services/session.server";
import {
archivePlatformNotification,
Expand Down Expand Up @@ -234,7 +235,8 @@ async function handleCreateAction(formData: FormData, userId: string, isPreview:
{ status: 400 }
);
}
return typedjson({ error: err.message }, { status: 500 });
logger.error("Failed to create platform notification", { error: err });
return typedjson({ error: "Something went wrong" }, { status: 500 });
}

if (isPreview) {
Expand All @@ -249,8 +251,13 @@ async function handleArchiveAction(formData: FormData) {
return typedjson({ error: "Missing notificationId" }, { status: 400 });
}

await archivePlatformNotification(notificationId);
return typedjson({ success: true });
try {
await archivePlatformNotification(notificationId);
return typedjson({ success: true });
} catch (error) {
logger.error("Failed to archive platform notification", { error, notificationId });
return typedjson({ error: "Failed to archive notification" }, { status: 500 });
}
}

async function handleDeleteAction(formData: FormData) {
Expand All @@ -259,8 +266,13 @@ async function handleDeleteAction(formData: FormData) {
return typedjson({ error: "Missing notificationId" }, { status: 400 });
}

await deletePlatformNotification(notificationId);
return typedjson({ success: true });
try {
await deletePlatformNotification(notificationId);
return typedjson({ success: true });
} catch (error) {
logger.error("Failed to delete platform notification", { error, notificationId });
return typedjson({ error: "Failed to delete notification" }, { status: 500 });
}
}

async function handlePublishNowAction(formData: FormData) {
Expand All @@ -269,8 +281,13 @@ async function handlePublishNowAction(formData: FormData) {
return typedjson({ error: "Missing notificationId" }, { status: 400 });
}

await publishNowPlatformNotification(notificationId);
return typedjson({ success: true });
try {
await publishNowPlatformNotification(notificationId);
return typedjson({ success: true });
} catch (error) {
logger.error("Failed to publish platform notification", { error, notificationId });
return typedjson({ error: "Failed to publish notification" }, { status: 500 });
}
}

async function handleEditAction(formData: FormData) {
Expand Down Expand Up @@ -310,7 +327,8 @@ async function handleEditAction(formData: FormData) {
{ status: 400 }
);
}
return typedjson({ error: err.message }, { status: 500 });
logger.error("Failed to update platform notification", { error: err });
return typedjson({ error: "Something went wrong" }, { status: 500 });
}

return typedjson({ success: true, id: result.value.id });
Expand Down
8 changes: 3 additions & 5 deletions apps/webapp/app/routes/api.v1.batches.$batchParam.results.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { z } from "zod";
import { ApiBatchResultsPresenter } from "~/presenters/v3/ApiBatchResultsPresenter.server";
import { ApiRunResultPresenter } from "~/presenters/v3/ApiRunResultPresenter.server";
import { authenticateApiRequest } from "~/services/apiAuth.server";
import { logger } from "~/services/logger.server";

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

return json(result);
} catch (error) {
if (error instanceof Error) {
return json({ error: error.message }, { status: 500 });
} else {
return json({ error: JSON.stringify(error) }, { status: 500 });
}
logger.error("Failed to load batch results", { error });
return json({ error: "Something went wrong" }, { status: 500 });
}
}
9 changes: 3 additions & 6 deletions apps/webapp/app/routes/api.v1.deployments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,10 @@ export async function action({ request, params }: ActionFunctionArgs) {
} catch (error) {
if (error instanceof ServiceValidationError) {
return json({ error: error.message }, { status: 400 });
} else if (error instanceof Error) {
logger.error("Error initializing deployment", { error: error.message });
return json({ error: `Internal server error: ${error.message}` }, { status: 500 });
} else {
logger.error("Error initializing deployment", { error: String(error) });
return json({ error: "Internal server error" }, { status: 500 });
}

logger.error("Error initializing deployment", { error });
return json({ error: "Internal server error" }, { status: 500 });
Comment thread
d-cs marked this conversation as resolved.
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
ApiAlertChannelPresenter,
ApiCreateAlertChannel,
} from "~/presenters/v3/ApiAlertChannelPresenter.server";
import { logger } from "~/services/logger.server";
import { authenticateApiRequestWithPersonalAccessToken } from "~/services/personalAccessToken.server";
import { CreateAlertChannelService } from "~/v3/services/alerts/createAlertChannel.server";
import { ServiceValidationError } from "~/v3/services/baseService.server";
Expand Down Expand Up @@ -88,9 +89,7 @@ export async function action({ request, params }: ActionFunctionArgs) {
return json({ error: error.message }, { status: 422 });
}

return json(
{ error: error instanceof Error ? error.message : "Internal Server Error" },
{ status: 500 }
);
logger.error("Failed to create alert channel", { error });
return json({ error: "Something went wrong" }, { status: 500 });
}
}
7 changes: 3 additions & 4 deletions apps/webapp/app/routes/api.v1.queues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { json } from "@remix-run/server-runtime";
import { type QueueItem } from "@trigger.dev/core/v3";
import { z } from "zod";
import { QueueListPresenter } from "~/presenters/v3/QueueListPresenter.server";
import { logger } from "~/services/logger.server";
import { createLoaderApiRoute } from "~/services/routeBuilders/apiBuilder.server";
import { ServiceValidationError } from "~/v3/services/baseService.server";

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

return json(
{ error: error instanceof Error ? error.message : "Internal Server Error" },
{ status: 500 }
);
logger.error("Failed to list queues", { error });
return json({ error: "Something went wrong" }, { status: 500 });
}
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
deleteInputStreamWaitpoint,
setInputStreamWaitpoint,
} from "~/services/inputStreamWaitpointCache.server";
import { logger } from "~/services/logger.server";
import { getRealtimeStreamInstance } from "~/services/realtime/v1StreamsGlobal.server";
import { createActionApiRoute } from "~/services/routeBuilders/apiBuilder.server";
import { parseDelay } from "~/utils/delays";
Expand Down Expand Up @@ -138,10 +139,9 @@ const { action, loader } = createActionApiRoute(
} catch (error) {
if (error instanceof ServiceValidationError) {
return json({ error: error.message }, { status: 422 });
} else if (error instanceof Error) {
return json({ error: error.message }, { status: 500 });
}

logger.error("Failed to create input-stream waitpoint", { error });
return json({ error: "Something went wrong" }, { status: 500 });
}
}
Expand Down
7 changes: 3 additions & 4 deletions apps/webapp/app/routes/api.v1.runs.$runId.tags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { z } from "zod";
import { prisma } from "~/db.server";
import { MAX_TAGS_PER_RUN } from "~/models/taskRunTag.server";
import { authenticateApiRequest } from "~/services/apiAuth.server";
import { logger } from "~/services/logger.server";

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

return json({ message: `Successfully set ${newTags.length} new tags.` }, { status: 200 });
} catch (error) {
return json(
{ error: error instanceof Error ? error.message : "Internal Server Error" },
{ status: 500 }
);
logger.error("Failed to add run tags", { error });
return json({ error: "Something went wrong" }, { status: 500 });
}
}
7 changes: 3 additions & 4 deletions apps/webapp/app/routes/api.v1.runs.$runParam.attempts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { ActionFunctionArgs } from "@remix-run/server-runtime";
import { json } from "@remix-run/server-runtime";
import { z } from "zod";
import { authenticateApiRequest } from "~/services/apiAuth.server";
import { logger } from "~/services/logger.server";
import { ServiceValidationError } from "~/v3/services/baseService.server";
import { CreateTaskRunAttemptService } from "~/v3/services/createTaskRunAttempt.server";

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

return json(
{ error: error instanceof Error ? error.message : "Internal Server Error" },
{ status: 500 }
);
logger.error("Failed to create run attempt", { error });
return json({ error: "Something went wrong" }, { status: 500 });
}
}
8 changes: 4 additions & 4 deletions apps/webapp/app/routes/api.v1.runs.$runParam.reschedule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { getApiVersion } from "~/api/versions";
import { prisma } from "~/db.server";
import { ApiRetrieveRunPresenter } from "~/presenters/v3/ApiRetrieveRunPresenter.server";
import { authenticateApiRequest } from "~/services/apiAuth.server";
import { logger } from "~/services/logger.server";
import { ServiceValidationError } from "~/v3/services/baseService.server";
import { RescheduleTaskRunService } from "~/v3/services/rescheduleTaskRun.server";

Expand Down Expand Up @@ -84,10 +85,9 @@ export async function action({ request, params }: ActionFunctionArgs) {
} catch (error) {
if (error instanceof ServiceValidationError) {
return json({ error: error.message }, { status: 400 });
} else if (error instanceof Error) {
return json({ error: error.message }, { status: 500 });
} else {
return json({ error: "An unknown error occurred" }, { status: 500 });
}

logger.error("Failed to reschedule run", { error });
return json({ error: "Something went wrong" }, { status: 500 });
}
}
8 changes: 3 additions & 5 deletions apps/webapp/app/routes/api.v1.runs.$runParam.result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { json } from "@remix-run/server-runtime";
import { z } from "zod";
import { ApiRunResultPresenter } from "~/presenters/v3/ApiRunResultPresenter.server";
import { authenticateApiRequest } from "~/services/apiAuth.server";
import { logger } from "~/services/logger.server";

const ParamsSchema = z.object({
/* This is the run friendly ID */
Expand Down Expand Up @@ -35,10 +36,7 @@ export async function loader({ request, params }: LoaderFunctionArgs) {

return json(result);
} catch (error) {
if (error instanceof Error) {
return json({ error: error.message }, { status: 500 });
} else {
return json({ error: JSON.stringify(error) }, { status: 500 });
}
logger.error("Failed to load run result", { error });
return json({ error: "Something went wrong" }, { status: 500 });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { prisma } from "~/db.server";
import { scheduleUniqWhereClause, scheduleWhereClause } from "~/models/schedules.server";
import { ViewSchedulePresenter } from "~/presenters/v3/ViewSchedulePresenter.server";
import { authenticateApiRequest } from "~/services/apiAuth.server";
import { logger } from "~/services/logger.server";

const ParamsSchema = z.object({
scheduleId: z.string(),
Expand Down Expand Up @@ -68,9 +69,7 @@ export async function action({ request, params }: ActionFunctionArgs) {

return json(presenter.toJSONResponse(result), { status: 200 });
} catch (error) {
return json(
{ error: error instanceof Error ? error.message : "Internal Server Error" },
{ status: 500 }
);
logger.error("Failed to activate schedule", { error });
return json({ error: "Something went wrong" }, { status: 500 });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { prisma } from "~/db.server";
import { scheduleUniqWhereClause, scheduleWhereClause } from "~/models/schedules.server";
import { ViewSchedulePresenter } from "~/presenters/v3/ViewSchedulePresenter.server";
import { authenticateApiRequest } from "~/services/apiAuth.server";
import { logger } from "~/services/logger.server";

const ParamsSchema = z.object({
scheduleId: z.string(),
Expand Down Expand Up @@ -68,9 +69,7 @@ export async function action({ request, params }: ActionFunctionArgs) {

return json(presenter.toJSONResponse(result), { status: 200 });
} catch (error) {
return json(
{ error: error instanceof Error ? error.message : "Internal Server Error" },
{ status: 500 }
);
logger.error("Failed to deactivate schedule", { error });
return json({ error: "Something went wrong" }, { status: 500 });
}
}
13 changes: 5 additions & 8 deletions apps/webapp/app/routes/api.v1.schedules.$scheduleId.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Prisma, prisma } from "~/db.server";
import { scheduleUniqWhereClause } from "~/models/schedules.server";
import { ViewSchedulePresenter } from "~/presenters/v3/ViewSchedulePresenter.server";
import { authenticateApiRequest } from "~/services/apiAuth.server";
import { logger } from "~/services/logger.server";
import { UpsertSchedule } from "~/v3/schedules";
import { ServiceValidationError } from "~/v3/services/baseService.server";
import { UpsertTaskScheduleService } from "~/v3/services/upsertTaskSchedule.server";
Expand Down Expand Up @@ -57,10 +58,8 @@ export async function action({ request, params }: ActionFunctionArgs) {
{ status: error.code === "P2025" ? 404 : 422 }
);
} else {
return json(
{ error: error instanceof Error ? error.message : "Internal Server Error" },
{ status: 500 }
);
logger.error("Failed to delete schedule", { error });
return json({ error: "Something went wrong" }, { status: 500 });
}
}
}
Expand Down Expand Up @@ -110,10 +109,8 @@ export async function action({ request, params }: ActionFunctionArgs) {
return json({ error: error.message }, { status: 422 });
}

return json(
{ error: error instanceof Error ? error.message : "Internal Server Error" },
{ status: 500 }
);
logger.error("Failed to upsert schedule", { error });
return json({ error: "Something went wrong" }, { status: 500 });
}
}
}
Expand Down
7 changes: 3 additions & 4 deletions apps/webapp/app/routes/api.v1.schedules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { CreateScheduleOptions, ScheduleObject } from "@trigger.dev/core/v3";
import { z } from "zod";
import { ScheduleListPresenter } from "~/presenters/v3/ScheduleListPresenter.server";
import { authenticateApiRequest } from "~/services/apiAuth.server";
import { logger } from "~/services/logger.server";
import { UpsertSchedule } from "~/v3/schedules";
import { ServiceValidationError } from "~/v3/services/baseService.server";
import { UpsertTaskScheduleService } from "~/v3/services/upsertTaskSchedule.server";
Expand Down Expand Up @@ -71,10 +72,8 @@ export async function action({ request }: ActionFunctionArgs) {
return json({ error: error.message }, { status: 422 });
}

return json(
{ error: error instanceof Error ? error.message : "Internal Server Error" },
{ status: 500 }
);
logger.error("Failed to create schedule", { error });
return json({ error: "Something went wrong" }, { status: 500 });
}
}

Expand Down
3 changes: 1 addition & 2 deletions apps/webapp/app/routes/api.v1.tasks.$taskId.trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,9 @@ const { action, loader } = createActionApiRoute(
return json({ error: error.message }, { status: error.status ?? 422 });
} else if (error instanceof OutOfEntitlementError) {
return json({ error: error.message }, { status: 422 });
} else if (error instanceof Error) {
return json({ error: error.message }, { status: 500 });
}

logger.error("Trigger task failed", { error });
return json({ error: "Something went wrong" }, { status: 500 });
}
}
Expand Down
Loading
Loading