From 8bfcec8ee64d87fe79a56f08a15e197e0e7aecc1 Mon Sep 17 00:00:00 2001 From: Lucas Smith Date: Wed, 5 Aug 2026 08:12:55 +1000 Subject: [PATCH 1/2] fix: add logging for errors on sign or complete (#3149) --- packages/trpc/server/field-router/router.ts | 71 ++++++++++------ .../trpc/server/recipient-router/router.ts | 83 +++++++++++-------- 2 files changed, 94 insertions(+), 60 deletions(-) diff --git a/packages/trpc/server/field-router/router.ts b/packages/trpc/server/field-router/router.ts index 39d207c5c..4d14e9de7 100644 --- a/packages/trpc/server/field-router/router.ts +++ b/packages/trpc/server/field-router/router.ts @@ -1,3 +1,4 @@ +import { AppError } from '@documenso/lib/errors/app-error'; import { createEnvelopeFields } from '@documenso/lib/server-only/field/create-envelope-fields'; import { deleteDocumentField } from '@documenso/lib/server-only/field/delete-document-field'; import { deleteTemplateField } from '@documenso/lib/server-only/field/delete-template-field'; @@ -613,23 +614,34 @@ export const fieldRouter = router({ * @private */ signFieldWithToken: procedure.input(ZSignFieldWithTokenMutationSchema).mutation(async ({ input, ctx }) => { - const { token, fieldId, value, isBase64, authOptions } = input; + try { + const { token, fieldId, value, isBase64, authOptions } = input; - ctx.logger.info({ - input: { + ctx.logger.info({ + input: { + fieldId, + }, + }); + + return await signFieldWithToken({ + token, fieldId, - }, - }); + value: value ?? '', + isBase64, + userId: ctx.user?.id, + authOptions, + requestMetadata: ctx.metadata.requestMetadata, + }); + } catch (err) { + // Log the error for debugging purposes. + ctx.logger.error({ + message: 'Error signing field with token', + error: err instanceof AppError ? `[${err.code}]: ${err.message}` : err, + }); - return await signFieldWithToken({ - token, - fieldId, - value: value ?? '', - isBase64, - userId: ctx.user?.id, - authOptions, - requestMetadata: ctx.metadata.requestMetadata, - }); + // Rethrow the error so that the client receives the appropriate error response. + throw err; + } }), /** @@ -638,18 +650,29 @@ export const fieldRouter = router({ removeSignedFieldWithToken: procedure .input(ZRemovedSignedFieldWithTokenMutationSchema) .mutation(async ({ input, ctx }) => { - const { token, fieldId } = input; + try { + const { token, fieldId } = input; - ctx.logger.info({ - input: { + ctx.logger.info({ + input: { + fieldId, + }, + }); + + return await removeSignedFieldWithToken({ + token, fieldId, - }, - }); + requestMetadata: ctx.metadata.requestMetadata, + }); + } catch (err) { + // Log the error for debugging purposes. + ctx.logger.error({ + message: 'Error removing signed field with token', + error: err instanceof AppError ? `[${err.code}]: ${err.message}` : err, + }); - return await removeSignedFieldWithToken({ - token, - fieldId, - requestMetadata: ctx.metadata.requestMetadata, - }); + // Rethrow the error so that the client receives the appropriate error response. + throw err; + } }), }); diff --git a/packages/trpc/server/recipient-router/router.ts b/packages/trpc/server/recipient-router/router.ts index 72c4f7296..b6b91a520 100644 --- a/packages/trpc/server/recipient-router/router.ts +++ b/packages/trpc/server/recipient-router/router.ts @@ -1,4 +1,5 @@ import { prepareCscRecipientSigning } from '@documenso/ee/server-only/signing/csc/prepare-recipient-signing'; +import { AppError } from '@documenso/lib/errors/app-error'; import { completeDocumentWithToken } from '@documenso/lib/server-only/document/complete-document-with-token'; import { rejectDocumentWithToken } from '@documenso/lib/server-only/document/reject-document-with-token'; import { createEnvelopeRecipients } from '@documenso/lib/server-only/recipient/create-envelope-recipients'; @@ -11,7 +12,6 @@ import { isTspEnvelope } from '@documenso/lib/types/signature-level'; import { unsafeBuildEnvelopeIdQuery } from '@documenso/lib/utils/envelope'; import { prisma } from '@documenso/prisma'; import { EnvelopeType } from '@prisma/client'; - import { ZGenericSuccessResponse, ZSuccessResponseSchema } from '../schema'; import { authenticatedProcedure, procedure, router } from '../trpc'; import { findRecipientSuggestionsRoute } from './find-recipient-suggestions'; @@ -590,47 +590,58 @@ export const recipientRouter = router({ .input(ZCompleteDocumentWithTokenMutationSchema) .output(ZCompleteDocumentWithTokenResponseSchema) .mutation(async ({ input, ctx }) => { - const { token, documentId, accessAuthOptions, nextSigner, recipientOverride } = input; + try { + const { token, documentId, accessAuthOptions, nextSigner, recipientOverride } = input; - ctx.logger.info({ - input: { - documentId, - }, - }); + ctx.logger.info({ + input: { + documentId, + }, + }); - // Branch on TSP envelopes before any SES side effects: TSP recipients - // can't complete via this route — they go through the CSC sync sign - // flow (`enterprise.csc.signEnvelope`). This route returns the redirect URL - // for the credential-scope OAuth round-trip. - const envelope = await prisma.envelope.findFirstOrThrow({ - where: { - ...unsafeBuildEnvelopeIdQuery({ type: 'documentId', id: documentId }, EnvelopeType.DOCUMENT), - recipients: { some: { token } }, - }, - select: { signatureLevel: true, internalVersion: true }, - }); + // Branch on TSP envelopes before any SES side effects: TSP recipients + // can't complete via this route — they go through the CSC sync sign + // flow (`enterprise.csc.signEnvelope`). This route returns the redirect URL + // for the credential-scope OAuth round-trip. + const envelope = await prisma.envelope.findFirstOrThrow({ + where: { + ...unsafeBuildEnvelopeIdQuery({ type: 'documentId', id: documentId }, EnvelopeType.DOCUMENT), + recipients: { some: { token } }, + }, + select: { signatureLevel: true, internalVersion: true }, + }); - if (isTspEnvelope(envelope)) { - return await prepareCscRecipientSigning({ - recipientToken: token, + if (isTspEnvelope(envelope)) { + return await prepareCscRecipientSigning({ + recipientToken: token, + requestMetadata: ctx.metadata.requestMetadata, + }); + } + + await completeDocumentWithToken({ + token, + id: { + type: 'documentId', + id: documentId, + }, + accessAuthOptions, + nextSigner, + recipientOverride, + userId: ctx.user?.id, requestMetadata: ctx.metadata.requestMetadata, }); + + return { status: 'SIGNED' as const }; + } catch (err) { + // Log the error for debugging purposes. + ctx.logger.error({ + message: 'Error completing document with token', + error: err instanceof AppError ? `[${err.code}]: ${err.message}` : err, + }); + + // Rethrow the error so that the client receives the appropriate error response. + throw err; } - - await completeDocumentWithToken({ - token, - id: { - type: 'documentId', - id: documentId, - }, - accessAuthOptions, - nextSigner, - recipientOverride, - userId: ctx.user?.id, - requestMetadata: ctx.metadata.requestMetadata, - }); - - return { status: 'SIGNED' as const }; }), /** From f0ab7c112e3c39656b0153b67fbf25fd9616e96f Mon Sep 17 00:00:00 2001 From: Lucas Smith Date: Wed, 5 Aug 2026 11:29:38 +1000 Subject: [PATCH 2/2] fix: add more logging for errors on sign or complete (#3151) --- packages/trpc/server/field-router/router.ts | 9 +++++++-- packages/trpc/server/recipient-router/router.ts | 5 ++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/trpc/server/field-router/router.ts b/packages/trpc/server/field-router/router.ts index 4d14e9de7..2028c37f6 100644 --- a/packages/trpc/server/field-router/router.ts +++ b/packages/trpc/server/field-router/router.ts @@ -636,9 +636,12 @@ export const fieldRouter = router({ // Log the error for debugging purposes. ctx.logger.error({ message: 'Error signing field with token', - error: err instanceof AppError ? `[${err.code}]: ${err.message}` : err, + error: err instanceof AppError ? `[${err.code}]: ${err.message}` : String(err), }); + // Raw console.log incase we're somehow deailing with a funky error object that doesn't serialize well. + console.log('Error signing field with token', err); + // Rethrow the error so that the client receives the appropriate error response. throw err; } @@ -668,9 +671,11 @@ export const fieldRouter = router({ // Log the error for debugging purposes. ctx.logger.error({ message: 'Error removing signed field with token', - error: err instanceof AppError ? `[${err.code}]: ${err.message}` : err, + error: err instanceof AppError ? `[${err.code}]: ${err.message}` : String(err), }); + console.log('Error removing signed field with token', err); + // Rethrow the error so that the client receives the appropriate error response. throw err; } diff --git a/packages/trpc/server/recipient-router/router.ts b/packages/trpc/server/recipient-router/router.ts index b6b91a520..e3ba84700 100644 --- a/packages/trpc/server/recipient-router/router.ts +++ b/packages/trpc/server/recipient-router/router.ts @@ -636,9 +636,12 @@ export const recipientRouter = router({ // Log the error for debugging purposes. ctx.logger.error({ message: 'Error completing document with token', - error: err instanceof AppError ? `[${err.code}]: ${err.message}` : err, + error: err instanceof AppError ? `[${err.code}]: ${err.message}` : String(err), }); + // Raw console.log incase we're somehow dealing with a funky error object that doesn't serialize well. + console.log('Error completing document with token', err); + // Rethrow the error so that the client receives the appropriate error response. throw err; }