Skip to content

OUT-3542: add Sentry context tags, breadcrumbs, and error categorization#215

Open
SandipBajracharya wants to merge 3 commits intomasterfrom
OUT-3542
Open

OUT-3542: add Sentry context tags, breadcrumbs, and error categorization#215
SandipBajracharya wants to merge 3 commits intomasterfrom
OUT-3542

Conversation

@SandipBajracharya
Copy link
Copy Markdown
Collaborator

@SandipBajracharya SandipBajracharya commented Apr 9, 2026

Summary

  • Add portalId, workspaceId, entityType, eventType, errorCategory tags to all Sentry error reports for dashboard filtering
  • Add sync breadcrumbs at key decision points (invoice creation, customer search/creation, product mapping, payment processing) to trace execution paths leading to errors
  • Expand FailedRecordCategoryType with RATE_LIMIT, VALIDATION, QB_API_ERROR, MAPPING_NOT_FOUND for finer error categorization
  • Enhance withErrorHandler to capture errors with category and source tags via Sentry.withScope
  • Add error source tracking (intuit/copilot) to getMessageAndCodeFromError for accurate QB API error detection
  • Isolate Sentry scope per portal in Trigger.dev cron flow (CronService._scheduleSinglePortal) to prevent breadcrumb/tag bleed across portals
  • Enrich threshold captureMessage in checkAndUpdateAttempt with full context tags (portalId, entityType, eventType, errorCategory) and extras (invoiceNumber, errorMessage, attempt)
  • Fix ANSI color codes ([32m/[39m) leaking into Vercel/New Relic logs by disabling colors in non-dev environments

DB Migration

Adds 4 new values to failed_record_category_types PostgreSQL enum:

ALTER TYPE "public"."failed_record_category_types" ADD VALUE IF NOT EXISTS 'rate_limit';
ALTER TYPE "public"."failed_record_category_types" ADD VALUE IF NOT EXISTS 'validation';
ALTER TYPE "public"."failed_record_category_types" ADD VALUE IF NOT EXISTS 'qb_api_error';
ALTER TYPE "public"."failed_record_category_types" ADD VALUE IF NOT EXISTS 'mapping_not_found';

Additive only — existing records and the others default are unaffected.

Test plan

  • Verify yarn build passes
  • Run migration on staging DB, verify SELECT enum_range(NULL::failed_record_category_types) returns all 7 values
  • Trigger a test webhook and verify Sentry event includes portalId and entityType tags
  • Trigger a failed sync retry up to threshold and verify captureMessage includes enriched tags/extras
  • Verify Vercel logs no longer contain ANSI escape codes
  • Verify breadcrumbs appear in Sentry event trail for invoice/customer/product/payment flows

🤖 Generated with Claude Code

…orization

Enrich Sentry error reports with structured context for easier debugging:

- Add portalId, workspaceId, entityType, eventType, errorCategory tags
- Add sync breadcrumbs at key decision points (invoice/customer/product/payment flows)
- Expand FailedRecordCategoryType with RATE_LIMIT, VALIDATION, QB_API_ERROR, MAPPING_NOT_FOUND
- Enhance error source tracking (intuit/copilot) in getMessageAndCodeFromError
- Isolate Sentry scope per portal in Trigger.dev cron flow to prevent breadcrumb bleed
- Fix ANSI color codes leaking into Vercel/New Relic logs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@linear
Copy link
Copy Markdown

linear bot commented Apr 9, 2026

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 9, 2026

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

Project Deployment Actions Updated (UTC)
quickbooks-sync Building Building Apr 9, 2026 9:42am
quickbooks-sync (dev) Ready Ready Preview, Comment Apr 9, 2026 9:42am

Request Review

@SandipBajracharya SandipBajracharya changed the title feat(OUT-3542): add Sentry context tags, breadcrumbs, and error categorization OUT-3542: add Sentry context tags, breadcrumbs, and error categorization Apr 9, 2026
SandipBajracharya and others added 2 commits April 9, 2026 14:37
…dcrumb capture

Move captureMessage from checkAndUpdateAttempt (before processing) to
intiateSync (after processing) so breadcrumbs from the actual execution
path are included in the Sentry event.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Only fire Sentry threshold report if record is still FAILED after
  final attempt (prevents spurious alerts on successful last retry)
- Use Sentry.withScope in webhook controller to isolate tags per
  request (prevents portalId contamination in concurrent webhooks)
- Skip setting errorSource tag when value is 'unknown' (reduces noise)
- Use actual booleans in breadcrumb data instead of string 'true'/'false'

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@priosshrsth priosshrsth left a comment

Choose a reason for hiding this comment

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

@SandipBajracharya couple of comments. But overall good job.

Comment on lines +31 to +39
// check if token is valid or not
const copilot = new CopilotAPI(token)
const tokenPayload = await copilot.getTokenPayload()
CustomLogger.info({
obj: { copilotApiCronToken: token, tokenPayload },
message:
'CronService#_scheduleSinglePortal | Copilot API token and payload',
})
if (!tokenPayload) throw new APIError(500, 'Encoded token is not valid') // this should trigger p-retry and re-run the function
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What we are doing here seems so wrong. I think we either set process.env.ASSEMBLY_ENV=local before line 32 and unset it after line 32. Or just use endpoints without sdks for cron. But looks like our whole flow is setup to require token. So I guess we are stuck with it.

info({ message, obj }: { message: string; obj?: any }) {
const consoleBody = [message]
if (obj) consoleBody.push(util.inspect(obj, { depth: null, colors: true }))
if (obj) consoleBody.push(util.inspect(obj, { depth: null, colors: isDev }))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Any reason for this?

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.

2 participants