diff options
Diffstat (limited to 'apps')
| -rw-r--r-- | apps/workers/workers/importWorker.ts | 27 |
1 files changed, 26 insertions, 1 deletions
diff --git a/apps/workers/workers/importWorker.ts b/apps/workers/workers/importWorker.ts index 2acbdcc1..047a8e39 100644 --- a/apps/workers/workers/importWorker.ts +++ b/apps/workers/workers/importWorker.ts @@ -10,6 +10,7 @@ import { or, } from "drizzle-orm"; import { Counter, Gauge, Histogram } from "prom-client"; +import { TRPCError } from "@trpc/server"; import { buildImpersonatingTRPCClient } from "trpc"; import { db } from "@karakeep/db"; @@ -71,6 +72,30 @@ function sleep(ms: number): Promise<void> { return new Promise((resolve) => setTimeout(resolve, ms)); } +/** + * Extract a safe, user-facing error message from an error. + * Avoids leaking internal details like database errors, stack traces, or file paths. + */ +function getSafeErrorMessage(error: unknown): string { + // TRPCError client errors are designed to be user-facing + if (error instanceof TRPCError && error.code !== "INTERNAL_SERVER_ERROR") { + return error.message; + } + + // Known safe validation errors thrown within the import worker + if (error instanceof Error) { + const safeMessages = [ + "URL is required for link bookmarks", + "Content is required for text bookmarks", + ]; + if (safeMessages.includes(error.message)) { + return error.message; + } + } + + return "An unexpected error occurred while processing the bookmark"; +} + export class ImportWorker { private running = false; private pollIntervalMs = 5000; @@ -441,7 +466,7 @@ export class ImportWorker { .set({ status: "failed", result: "rejected", - resultReason: String(error), + resultReason: getSafeErrorMessage(error), completedAt: new Date(), }) .where(eq(importStagingBookmarks.id, staged.id)); |
