Context
Split out of the review on be#941 (be#932's fallback fix for malformed Timeslot data). That PR made sendEmailIntroduction/sendEmailSuggestion degrade gracefully (fallback string + ERROR_EMAIL alert) when the volunteer's schedule data is malformed, rather than throwing and silently blocking the whole match/introduction email.
getLanguages(volunteer.deal?.dealLanguage ?? []) and getOptionItems(volunteer.deal?.dealSkill ?? [], "skill") in src/services/notify/events/email-introduction.ts have the identical failure mode: if a dealLanguage/dealSkill row's language/skill relation is null (e.g. an orphaned FK after a deletion), pl.language.id / pa[entityName].id throws a TypeError. That throw isn't wrapped by anything — it propagates out of sendEmailIntroduction, is caught by the outer try/catch in the MATCHED-status handler (src/server/routes/m2m/opportunity-volunteer.routes.ts), which removes the just-logged Communication row and drops the email entirely. Same class of bug be#932 was raised to fix, just for a sibling field.
Ask
Decide whether getLanguages/getOptionItems (used for volunteerLanguage/volunteerSkills in the introduction email) warrant the same resolveScheduleOrAlert-style treatment (fallback string + ERROR_EMAIL alert via the pattern established in be#941 — src/services/notify/resolve-schedule-or-alert.ts), or whether this specific failure mode is rare/low-risk enough to leave as-is.
Context
Split out of the review on be#941 (be#932's fallback fix for malformed
Timeslotdata). That PR madesendEmailIntroduction/sendEmailSuggestiondegrade gracefully (fallback string +ERROR_EMAILalert) when the volunteer's schedule data is malformed, rather than throwing and silently blocking the whole match/introduction email.getLanguages(volunteer.deal?.dealLanguage ?? [])andgetOptionItems(volunteer.deal?.dealSkill ?? [], "skill")insrc/services/notify/events/email-introduction.tshave the identical failure mode: if adealLanguage/dealSkillrow'slanguage/skillrelation isnull(e.g. an orphaned FK after a deletion),pl.language.id/pa[entityName].idthrows aTypeError. That throw isn't wrapped by anything — it propagates out ofsendEmailIntroduction, is caught by the outer try/catch in the MATCHED-status handler (src/server/routes/m2m/opportunity-volunteer.routes.ts), which removes the just-loggedCommunicationrow and drops the email entirely. Same class of bug be#932 was raised to fix, just for a sibling field.Ask
Decide whether
getLanguages/getOptionItems(used forvolunteerLanguage/volunteerSkillsin the introduction email) warrant the sameresolveScheduleOrAlert-style treatment (fallback string +ERROR_EMAILalert via the pattern established in be#941 —src/services/notify/resolve-schedule-or-alert.ts), or whether this specific failure mode is rare/low-risk enough to leave as-is.