{"record":{"id":"9b65d1e68a572fdc","repo":"kriasoft/react-starter-kit","slug":"failed-to-send-email-error-instanceof-error-e","errorCode":null,"errorMessage":"Failed to send email: ${error instanceof Error ? error.message : \"Unknown error\"}","messagePattern":"Failed to send email: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/api/lib/email.ts","lineNumber":72,"sourceCode":"\n  try {\n    const result = await resend.emails.send({\n      from: options.from || env.RESEND_EMAIL_FROM,\n      to: options.to,\n      subject: options.subject,\n      html: options.html,\n      text: options.text,\n    });\n\n    if (result.error) {\n      throw new Error(\n        `Resend API error: ${result.error.message || result.error.name || \"Unknown error\"}`,\n      );\n    }\n\n    return result;\n  } catch (error) {\n    throw new Error(\n      `Failed to send email: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n      { cause: error },\n    );\n  }\n}\n\n/**\n * Send email verification message.\n *\n * @param env Environment variables\n * @param options User and verification URL (should be time-limited, signed token)\n */\nexport async function sendVerificationEmail(\n  env: TemplateEnv,\n  options: {\n    user: { email: string; name?: string };\n    url: string;\n  },","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/kriasoft/react-starter-kit/blob/0aa7603435f16159ad0b8fef68fb7f6280be7ca1/apps/api/lib/email.ts#L54-L90","documentation":"The catch-all in sendEmail wraps ANY failure from the try block — including the Resend API error thrown above it and network/fetch failures — into 'Failed to send email: <inner message>' with the original attached as `cause`. The generic outer message plus a nested cause means callers often see the same failure twice in the chain.","triggerScenarios":"Any sendEmail call where resend.emails.send() rejects (network timeout, Workers fetch failure, DNS, TLS) or where the inner result.error branch threw — the wrapper re-wraps that too.","commonSituations":"Cloudflare Worker egress blocked or outbound fetch hiccup, Resend returning a 5xx, or a developer logging only error.message and missing the detailed `cause` with the real reason.","solutions":["Inspect error.cause — the original exception (including the 'Resend API error: ...' message) is preserved there","Check network egress from the Worker environment and Resend status for outages","Differentiate the wrapping: match on cause or rethrow the provider error as-is so callers can distinguish validation vs network vs provider failures","Add retry with exponential backoff for transient (network/5xx) failures before surfacing to the user"],"exampleFix":"// before\ncatch (error) {\n  throw new Error(`Failed to send email: ${error instanceof Error ? error.message : \"Unknown error\"}`, { cause: error });\n}\n// after\ncatch (error) {\n  if (error instanceof Error && error.message.startsWith(\"Resend API error:\")) throw error; // don't double-wrap\n  throw new Error(`Failed to send email: ${error instanceof Error ? error.message : \"Unknown error\"}`, { cause: error });\n}","handlingStrategy":"try-catch","validationCode":"if (!env.RESEND_API_KEY || !env.RESEND_EMAIL_FROM) {\n  throw new Error('Email provider not configured (RESEND_API_KEY / RESEND_EMAIL_FROM missing)');\n}","typeGuard":"function isSendFailure(error: unknown): error is Error & { cause?: unknown } {\n  return error instanceof Error && error.message.startsWith('Failed to send email:');\n}","tryCatchPattern":"try {\n  await sendEmail(env, options);\n} catch (error) {\n  const root = error instanceof Error && error.cause instanceof Error ? error.cause : error;\n  console.error('Email send failed:', root); // read cause for the real reason\n  const retryable = !(root instanceof Error && root.message.startsWith('Resend API error:'));\n  if (retryable) await backoffRetry(() => sendEmail(env, options), 3);\n}","preventionTips":["Always inspect error.cause when handling this error — the outer message is generic","Retry only network/5xx-shaped failures, never validation or provider 4xx config errors","Queue emails (durable outbox) instead of sending inline so transient failures can be retried","Alert on send failures rather than silently swallowing them"],"tags":["resend","network","wrapper-error","email"],"backgroundTag":"failed-to-send-email","analyzedSha":"0aa7603435f16159ad0b8fef68fb7f6280be7ca1","analyzedAt":"2026-08-31T21:50:55.742Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}