Skip to content

ENG-2489: Improve error messages for misconfigured dynamic erasure email connectors#7779

Merged
JadeCara merged 10 commits intomainfrom
eng-2489/improve-dynamic-erasure-email-error-messages
Apr 1, 2026
Merged

ENG-2489: Improve error messages for misconfigured dynamic erasure email connectors#7779
JadeCara merged 10 commits intomainfrom
eng-2489/improve-dynamic-erasure-email-error-messages

Conversation

@JadeCara
Copy link
Copy Markdown
Contributor

@JadeCara JadeCara commented Mar 27, 2026

Ticket ENG-2489

Description Of Changes

When a dynamic erasure email connector is incorrectly configured (e.g., empty secrets), the error message currently shows a generic Pydantic validation error with no indication of which connector is broken. This makes debugging difficult for end users.

This PR improves error handling across the dynamic erasure email flow to always identify the misconfigured connector by key.

Code Changes

  • Wrap DynamicErasureEmailConnector.get_config() to catch ValidationError and re-raise with the connector key in the message
  • Handle per-connector errors in send_email_batch so one broken connector doesn't block others
  • Always requeue successfully-processed privacy requests even when a connector fails
  • Treat misconfigured connectors as needing email send in needs_batch_email_send to fail visibly rather than silently skip
  • Add test for improved error message on empty secrets

Steps to Confirm

  1. Create a dynamic erasure email connector with empty secrets
  2. Trigger an erasure privacy request
  3. Confirm the error message includes the connector key (e.g., Dynamic erasure email connector 'my_connector' is incorrectly configured: ...)
  4. Confirm other correctly-configured connectors still process successfully

Pre-Merge Checklist

  • Issue requirements met
  • All CI pipelines succeeded
  • CHANGELOG.md updated
    • Add a db-migration This indicates that a change includes a database migration label to the entry if your change includes a DB migration
    • Add a high-risk This issue suggests changes that have a high-probability of breaking existing code label to the entry if your change includes a high-risk change (i.e. potential for performance impact or unexpected regression) that should be flagged
    • Updates unreleased work already in Changelog, no new entry necessary
  • UX feedback:
    • No UX review needed
  • Followup issues:
    • No followup issues
  • Database migrations:
    • No migrations
  • Documentation:
    • No documentation updates required

🤖 Generated with Claude Code

…ail connectors

Wrap DynamicErasureEmailConnector.get_config() to include the connector
key in validation errors, so users can identify which connector is
misconfigured. Also improve resilience of the batch email send and
needs_batch_email_send flows: handle per-connector errors so one broken
connector doesn't block others, always requeue successfully-processed
requests, and treat misconfigured connectors as needing email to fail
visibly rather than silently skipping.

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

vercel bot commented Mar 27, 2026

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

2 Skipped Deployments
Project Deployment Actions Updated (UTC)
fides-plus-nightly Ignored Ignored Preview Mar 31, 2026 6:24pm
fides-privacy-center Ignored Ignored Mar 31, 2026 6:24pm

Request Review

Jade Wibbels and others added 4 commits March 27, 2026 16:47
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The per-connector error handling refactor inadvertently moved
requeue_privacy_requests_after_email_send before the failure check,
causing privacy requests to advance toward completion even when
email sends failed. Move requeue after the has_failure guard to
preserve the original behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The batch service now catches exceptions per-connector instead of
letting them propagate. Update integration tests to assert
EmailExitState.email_send_failed instead of pytest.raises, since
errors are still surfaced via privacy request status and execution logs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@JadeCara JadeCara marked this pull request as ready for review March 30, 2026 21:16
@JadeCara JadeCara requested a review from a team as a code owner March 30, 2026 21:16
@JadeCara JadeCara requested review from galvana and removed request for a team March 30, 2026 21:16
Copy link
Copy Markdown

@claude claude bot left a comment

Choose a reason for hiding this comment

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

Code Review: Improve error messages for misconfigured dynamic erasure email connectors

The goals here are solid — surfacing the connector key in Pydantic validation errors, making send_email_batch process connectors independently so one failure doesn't block others, and routing misconfigured connectors into the visible error path. The approach is good, but there is one critical runtime bug introduced by the refactor.


Critical (must fix)

requeue_privacy_requests_after_email_send is called after the session is closed (see inline comment on line 118 of email_batch_service.py).

The with self.get_new_session() as session: block closes at line 114. Lines 115–119 are outside it, so on the success path, session is already closed and privacy_requests is a Query bound to that closed session. requeue_privacy_requests_after_email_send iterates the query and calls privacy_request.save(db=db) — this will raise a DetachedInstanceError at runtime on every successful batch send.

The fix is to move the if has_failure: check and the requeue_privacy_requests_after_email_send(...) call back inside the with self.get_new_session() as session: block. The original code had this in the correct place inside the try: block.

Note: the integration tests for the failure path mock requeue_privacy_requests_after_email_send, which means this regression won't be caught by those tests. Only a successful end-to-end run would surface it.


Suggestions

  • Broad except Exception (inline on line 90): transient infrastructure errors are now silently absorbed instead of allowing Celery to retry. Worth documenting as a known trade-off, or narrowing the catch for certain error types.
  • "third_party_vendor_name" assertion (inline on test_dynamic_erasure_email_connector.py line 290): couples the test to Pydantic's internal ValidationError formatting — consider removing it since the surrounding assertions already cover the intent.
  • Missing test for needs_batch_email_send exception path: the new except Exception block in request_runner_service.py (lines 1174–1183) that treats check errors as "needing email" has no unit test. A test verifying that an exception during needs_email() still returns True would prevent regressions.

Jade Wibbels and others added 2 commits March 30, 2026 15:50
- Move has_failure check and requeue call back inside session scope to fix pre-existing closed-session bug
- Narrow except clause from broad Exception to (MessageDispatchException, DynamicErasureEmailConnectorException)

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

@galvana galvana left a comment

Choose a reason for hiding this comment

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

This is a nice set of improvements to the error handling. I spent some time going back and for with Claude about what would happen if email connector A succeeds and B fails. As I understand it, today we would just re-send the email for connector A the next time the email batch kicks off. This is a problem that existed before your current change so we don't have to fix it now, but it's something to think about.

When erasure email connector A succeeds but connector B fails, all
privacy requests are set to error. On retry (after operator reset),
connector A would re-send emails it already sent. This adds a check
for existing complete ExecutionLogs per connector before sending,
preventing duplicate emails on retry.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@JadeCara JadeCara added this pull request to the merge queue Apr 1, 2026
Merged via the queue into main with commit 9bc7210 Apr 1, 2026
61 of 63 checks passed
@JadeCara JadeCara deleted the eng-2489/improve-dynamic-erasure-email-error-messages branch April 1, 2026 16:33
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