Skip to content

adjust logging#1073

Merged
elie222 merged 1 commit intomainfrom
chore/log
Dec 7, 2025
Merged

adjust logging#1073
elie222 merged 1 commit intomainfrom
chore/log

Conversation

@elie222
Copy link
Owner

@elie222 elie222 commented Dec 5, 2025

Adjust logging to record raw error objects across web app services and remove errorMessage from apps/web/app/api/user/stats/newsletters/route.ts:getNewsletterCounts

Replace string error messages with raw error objects in warnings and errors across API handlers, actions, assistants, and providers, and remove the errorMessage field from one structured log; bump version to v2.21.49.

📍Where to Start

Start with the logging change in getNewsletterCounts in route.ts, then scan similar logger updates in action and assistant utilities.


📊 Macroscope summarized cef1f01. 13 files reviewed, 25 issues evaluated, 19 issues filtered, 1 comment posted

🗂️ Filtered Issues

apps/web/app/api/user/stats/newsletters/route.ts — 0 comments posted, 1 evaluated, 1 filtered
  • line 203: limitClause is built via string interpolation without validating that options.limit is non‑negative. A negative value (e.g., ?limit=-1) passes Zod coercion and is truthy, yielding LIMIT -1, which can cause a runtime SQL error in PostgreSQL (LIMIT must not be negative). Validate and clamp to a non‑negative integer (and optionally cap to a sane maximum) before constructing the clause. [ Out of scope ]
apps/web/app/api/watch/controller.ts — 1 comment posted, 3 evaluated, 2 filtered
  • line 26: On the Microsoft provider success path, the code returns the Date from createManagedOutlookSubscription but does not persist it to the database (e.g., prisma.emailAccount.update({ watchEmailsExpirationDate })). This creates contract/side‑effect asymmetry with the non‑Microsoft path, which explicitly updates watchEmailsExpirationDate. If createManagedOutlookSubscription does not itself persist the expiration (or subscription id), the database remains stale, making downstream logic that relies on DB state (e.g., cleanup/scheduling/unwatch flows) believe the account is not being watched. [ Out of scope ]
  • line 31: On the non‑Microsoft provider success path, only result.expirationDate is persisted. If provider.watchEmails() also returns a subscription identifier (commonly required to unwatch), it is silently dropped with no explicit rejection or comment. This risks making later unwatch operations impossible if they rely on a stored watchEmailsSubscriptionId, and it violates the requirement to avoid silent data loss at data‑conversion boundaries. [ Out of scope ]
apps/web/utils/actions/ai-rule.ts — 0 comments posted, 4 evaluated, 3 filtered
  • line 264: When prompts differ textually but the AI diff yields no rule changes, the function returns early without updating emailAccount.rulesPrompt. This contradicts the documented flow step to update the user's prompt and causes the user's edited prompt text to be discarded. The problematic early return occurs after computing the diff when !diff.addedRules.length && !diff.editedRules.length && !diff.removedRules.length, skipping the DB update of rulesPrompt even though oldPromptFile !== rulesPrompt. [ Out of scope ]
  • line 397: The function updates emailAccount.rulesPrompt and reports counts based on intended operations rather than confirmed successes, leading to inconsistent state and misleading results when some operations fail but are caught. Specifically: (1) In the create loop, errors other than duplicates are caught and only logged, yet createdRules is still reported as addedRules?.length and the prompt is updated; (2) In the delete path, if deleteRule throws a non-NotFound error, it is caught and the loop continues, removeRulesCount is incremented, and the prompt is later updated. This can persist a prompt that implies changes that did not actually apply, and overstate createdRules/removedRules in the returned response. [ Low confidence ]
  • line 411: The logging change passes the raw error object to logger.error instead of a stringified/serialized representation. If the logger expects JSON-serializable data, logging an Error with circular references or large nested properties can cause serialization failures or drop useful context, potentially throwing during logging or truncating logs. Previously it logged error instanceof Error ? error.message : String(error), which guaranteed serializable output. [ Code style ]
apps/web/utils/actions/report.ts — 0 comments posted, 1 evaluated, 1 filtered
  • line 176: Unbounded parallel requests when enriching labels can trigger Gmail API rate limits and intermittent failures. In fetchGmailLabels, each user label is processed with an individual gmail.users.labels.get call inside a Promise.all over the entire userLabels set. With many labels, this can create a burst of concurrent requests, causing 429s or quota errors. Although per-label failures are caught and zeroed, this can degrade accuracy (counts all zero) and produce noisy logs. Use bounded concurrency (e.g., a limiter) or batch/sequential processing to keep request rates within API limits. [ Low confidence ]
apps/web/utils/ai/assistant/process-user-request.ts — 0 comments posted, 2 evaluated, 1 filtered
  • line 46: Possible crash when messages is empty: the code unconditionally accesses messages[messages.length - 1].role at line 46. If messages.length === 0, messages[messages.length - 1] is undefined and reading .role throws a runtime TypeError. The function signature allows any messages: { role: "assistant" | "user"; content: string }[] (including an empty array). Add a guard for empty arrays before indexing, or enforce non-empty via validation. [ Out of scope ]
apps/web/utils/ai/mcp/mcp-tools.ts — 0 comments posted, 3 evaluated, 3 filtered
  • line 105: Silent data loss when multiple connections exist for the same integration: toolsByIntegration is keyed by integration.id, and each iteration calls toolsByIntegration.set(integration.id, ...). If there are multiple mcpConnection rows for the same integration.id, later entries will overwrite earlier ones, dropping tools from prior connections without warning. Consider merging tool sets per integration or guarding against duplicates. [ Out of scope ]
  • line 111: Passing a raw error object to the logger may cause serialization/logging to throw (e.g., if the logger JSON-serializes the meta and the error contains circular references). This exception would be thrown inside the inner catch block, potentially escaping and triggering the outer catch; combined with the current outer error path, this can lead to leaked clients and lost processing of other integrations. [ Low confidence ]
  • line 134: Possible resource leak: if an exception escapes the outer try/catch after one or more MCP clients have been created and pushed to clients, the outer catch returns a cleanup that is a no-op, so those clients will never be closed. This can happen if any code after client creation throws outside the inner per-integration try/catch (e.g., a logging failure or an unexpected error during merging). Ensure previously created clients are closed on the outer error path. [ Out of scope ]
apps/web/utils/ai/report/fetch.ts — 0 comments posted, 2 evaluated, 2 filtered
  • line 121: Inner catch logs the raw error object via logger.warn("Failed to process draft:", { error });. If the logger attempts to serialize contextual objects (e.g., JSON.stringify), a non-serializable or circular error can cause logger.warn to throw. Because this call is inside the try block for the whole function, a thrown log here would escape the inner catch and abort the entire outer try, falling into the outer catch and potentially returning an empty list — losing any templates accumulated so far. Previously, the code stringified error safely. Consider logging a safe projection (e.g., error instanceof Error ? { message: error.message, stack: error.stack } : { error: String(error) }) to avoid logger-induced exceptions. [ Low confidence ]
  • line 128: Outer catch logs the raw error object via logger.warn("Failed to fetch email templates:", { error });. If the logger serializes the context and the error is non-serializable or circular, logger.warn may throw, causing the function to reject instead of returning [] as intended by the catch. Previously, the code logged a stringified/normalized error, avoiding this risk. Use a safe projection of the error to ensure logging cannot throw and the function reliably returns an empty array on failure. [ Low confidence ]
apps/web/utils/email/microsoft.ts — 0 comments posted, 2 evaluated, 1 filtered
  • line 1427: Potential runtime TypeError when accessing message.headers.from without verifying message.headers exists. If any message lacks a headers object, message.headers.from will throw. Add a guard (e.g., check message.headers and message.headers.from or use optional chaining) before constructing the return value. [ Out of scope ]
apps/web/utils/user/merge-premium.ts — 0 comments posted, 3 evaluated, 2 filtered
  • line 97: isOnHigherTier(targetTier, sourceTier) is called when both users have a premiumId (branch starting at if (sourceUser.premiumId && targetUser.premiumId)), but there is no explicit check that sourceUser.premium and targetUser.premium are non-null. If a premiumId exists but the related premium record is not loaded/resolvable, sourceTier or targetTier may be undefined, potentially causing isOnHigherTier to throw or mis-evaluate. Add explicit null checks (or defaulting) before invoking isOnHigherTier. [ Low confidence ]
  • line 170: In the premium admin transfer branch, two logically coupled updates are issued concurrently: prisma.premium.update({ data: { admins: { connect: { id: targetUserId }}}}) and conditionally prisma.user.update({ data: { premiumAdminId: sourceUser.premiumAdminId }}). Without a transaction and with parallel execution, failure of either can leave an inconsistent state (e.g., premiumAdminId points to an admin group the user is not actually connected to as admin). Execute these updates within a single prisma.$transaction([...]) to ensure consistency, and consider ordering or idempotency checks if needed. [ Low confidence ]
apps/web/utils/webhook/process-history-item.ts — 0 comments posted, 4 evaluated, 3 filtered
  • line 49: markMessageAsProcessing({ userEmail, messageId }) sets a processing marker, but there is no corresponding clear/unmark on any success or early-return path, nor in a finally. If the marker is not TTL-based, any early return (e.g., ignored sender, not-inbox, assistant paths) or thrown error will leave the message permanently marked as processing, causing future attempts to skip processing (isFree === false). Add a finally that reliably clears the marker on all exit paths, or ensure the helper uses a short TTL. [ Low confidence ]
  • line 121: processAssistantEmail(...) is returned without await, so any rejection thrown by that promise will bypass the surrounding try/catch and skip the provider-specific not-found handling and error logging. This creates inconsistent error handling compared to other paths (e.g., handleOutboundMessage is awaited) and can lead to unhandled rejection at the call site. Replace return processAssistantEmail(...) with await processAssistantEmail(...) followed by return; to keep errors within the try/catch scope. [ Low confidence ]
  • line 175: Same as above: extractEmailAddress(parsedMessage.headers.from) result is used in prisma.newsletter.findUnique({ where: { email_emailAccountId: { email: sender, emailAccountId } } }) without verifying sender is a non-empty string. If sender is undefined, Prisma will throw at runtime. Add a guard before querying or skip categorization when the email cannot be extracted. [ Low confidence ]

Summary by CodeRabbit

  • Chores
    • Improved error logging across multiple modules to capture full error objects instead of error messages only, providing better debugging information.
    • Version bumped to v2.21.49.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Dec 5, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
inbox-zero Ready Ready Preview Dec 5, 2025 10:35pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 5, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

This PR updates error logging across 13 TypeScript files and version.txt by replacing formatted error message strings with raw error objects in logger calls. No control flow changes occur; only the logged error payloads are modified to preserve richer debugging information.

Changes

Cohort / File(s) Summary
API & Route Handlers
apps/web/app/api/user/stats/newsletters/route.ts, apps/web/app/api/watch/controller.ts
Updated logger calls to pass raw error objects instead of error message strings in catch blocks
Action Utilities
apps/web/utils/actions/ai-rule.ts, apps/web/utils/actions/report.ts
Modified error logging in saveRulesPromptAction, createRulesAction, and fetch Gmail label/signature functions to log full error objects
AI Assistant Utilities
apps/web/utils/ai/assistant/chat.ts, apps/web/utils/ai/assistant/process-user-request.ts
Changed error logging payloads from message strings to raw error objects in catch blocks
AI Integration Utilities
apps/web/utils/ai/mcp/mcp-tools.ts, apps/web/utils/ai/report/fetch.ts
Updated logger calls to pass error objects directly instead of extracting error.message
Email/OAuth Services
apps/web/utils/email/microsoft.ts, apps/web/utils/gmail/signature-settings.ts, apps/web/utils/outlook/subscription-manager.ts
Modified getSignatures, getGmailSignatures, and subscription cancellation error logging to use raw error objects
User & Webhook Utilities
apps/web/utils/user/merge-premium.ts, apps/web/utils/webhook/process-history-item.ts
Updated catch block error logging to pass error objects instead of formatted message strings
Version
version.txt
Version bump from v2.21.48 to v2.21.49

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

  • Highly homogeneous changes across files (identical error logging pattern applied consistently)
  • No control-flow modifications or functional logic changes
  • Each file follows the same transformation pattern (error.message → error)
  • Volume of files is manageable despite repetition

Possibly related PRs

  • Adjust logs #956: Implements the same core change—switching error logging from formatted error message strings to raw error objects across multiple files
  • Adjust logs #1006: Coordinates with this PR by updating the logger's serializeError functionality to properly handle and serialize raw error objects passed from these logging sites
  • Upgrade packages #1068: Modifies the same file (apps/web/utils/ai/mcp/mcp-tools.ts) for experimental_createMCPClient import changes

Poem

🐰 A rabbit hops through logs so fine,
Raw errors now in every line,
No messages cut short or small—
Full objects logged to catch 'em all!
Debugging's sweeter, debugging's bright,

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'adjust logging' accurately reflects the main change—updating error logging across multiple files from logging error messages to logging full error objects.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/log

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 14 files

error: errorMessage,
error,
});
await cleanupInvalidTokens({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cleanupInvalidTokens(...) is awaited inside the catch. If it throws, watchEmails rejects instead of returning { success: false, error }. Consider wrapping it in its own try/catch (and log) so the function preserves its return contract.

-      await cleanupInvalidTokens({
-        emailAccountId,
-        reason: isInvalidGrant ? "invalid_grant" : "insufficient_permissions",
-        logger,
-      });
+      try {
+        await cleanupInvalidTokens({
+          emailAccountId,
+          reason: isInvalidGrant ? "invalid_grant" : "insufficient_permissions",
+          logger,
+        });
+      } catch (cleanupError) {
+        logger.error("Failed to cleanup invalid tokens", {
+          emailAccountId,
+          providerName: provider.name,
+          error: cleanupError,
+        });
+        captureException(cleanupError);
+      }

🚀 Reply to ask Macroscope to explain or update this suggestion.

👍 Helpful? React to give us feedback.

@elie222 elie222 merged commit 401001c into main Dec 7, 2025
18 checks passed
@elie222 elie222 deleted the chore/log branch December 7, 2025 00:30
This was referenced Dec 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments