You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

发送邮箱验证链接时遇“Can't set headers after they are sent”错误求助

Fixing "Can't set headers after they are sent" & Unhandled Rejection Errors in Express

Hey there! That classic Can't set headers after they are sent error is one of the most common gotchas when working with Express—let’s break down exactly what’s happening and how to fix it for your email verification flow.

What’s Causing This?

This error pops up when your Express server tries to send more than one HTTP response for a single client request. For example:

  • You call res.send() or res.json() to confirm the verification email was sent, but then another piece of code (like an async callback or unguarded logic) tries to send another response later.
  • An unhandled Promise rejection (from your email-sending code) is causing unexpected code execution that triggers a duplicate response.

The "Unhandled rejection" error is tied to this too—your email-sending Promise is failing, but you aren’t catching that failure, so it’s spilling over and messing up your response flow.

Step-by-Step Fixes

1. Ensure Only One Response Per Request

Double-check your verification route code for accidental duplicate responses. Here’s a common mistake to watch out for:

// ❌ Wrong: Sends two responses
app.post('/send-verification', (req, res) => {
  sendVerificationEmail(req.user.email)
    .then(() => {
      res.json({ success: true }); // First response
    });
  res.json({ message: "Verification email queued" }); // Second response—this causes the error!
});

Fix it by making sure your response logic is properly contained in the Promise chain, and use return to stop further code execution:

// ✅ Correct: Single response, with proper flow control
app.post('/send-verification', (req, res) => {
  sendVerificationEmail(req.user.email)
    .then(() => {
      return res.json({ success: true }); // Return ensures no further code runs here
    })
    .catch(err => {
      return res.status(500).json({ error: "Failed to send verification email" });
    });
});

2. Catch All Promise Rejections

The "Unhandled rejection" error means your email-sending Promise is throwing an error that isn’t being caught. Use async/await with try/catch for cleaner, more reliable error handling:

// ✅ Even better: Async/Await with Try/Catch
app.post('/send-verification', async (req, res) => {
  try {
    await sendVerificationEmail(req.user.email);
    return res.json({ success: true });
  } catch (err) {
    console.error("Email send failure:", err); // Log the error for debugging
    return res.status(500).json({ error: "Could not send verification email" });
  }
});

This way, any errors in your email-sending logic are properly handled, and you won’t get unhandled rejection warnings or accidental duplicate responses.

3. Check for Middleware Conflicts

If you’re using middleware, make sure none of your previous middleware functions are already sending a response for the same request. For example, a validation middleware that sends an error response but doesn’t stop the request from reaching your verification route.

Quick Recap

  • Rule #1: Every request gets exactly one response—no exceptions.
  • Rule #2: Always catch errors in async/Promise code to avoid unhandled rejections.
  • Use return after sending responses to prevent unintended code execution.

内容的提问来源于stack exchange,提问作者Fenil Shah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:13:34