Next.js API路由报错:无法将Symbol值转换为字符串求助
在Next.js的API路由目录中遇到TypeError错误,反复收到提示:Cannot convert a Symbol value to a string,但代码中并未显式使用Symbol类型,也没有手动的字符串转换操作。以下是相关代码及错误信息,求排查思路:
API路由代码(/api/email/meetingNotification)
import { NextResponse } from 'next/server'; import MeetingNotification from "../../../../../emails/meetingNotification"; import { resend } from '@/utils/resend'; interface EmailData { schoolName: string; email: string; clubName: string; meetingDate: string; meetingTime: string; meetingDescription: string; meetingName: string; location: string; type: string; mandatory: boolean; meetingId: string; clubCode: string; } export async function POST(request: Request) { const emails: EmailData[] = await request.json(); try { const emailPromises = emails.map(({ schoolName, email, clubName, meetingDate, meetingTime, meetingDescription, meetingName, location, type, mandatory, meetingId, clubCode }: EmailData) => { return resend.emails.send({ from: `${clubName} <${clubCode}@clubcentric.org>`, to: email, subject: `A new meeting has been scheduled for ${clubName}`, react: MeetingNotification({ schoolName, location, type, clubName, meetingDate: new Date(meetingDate).toDateString(), meetingId, meetingTime, meetingDescription, meetingName, mandatory, }) }); }); await Promise.all(emailPromises); return NextResponse.json({ status: 'Ok' }, { status: 200 }); } catch (e: unknown) { console.error('Failed to send emails:', e); return NextResponse.json( { error: 'Internal server error. Please try resending the emails.' }, { status: 500 } ); } }
sendMeetingNotification()函数代码
if (meetingData.meeting_data.push_notification) { const { data: membershipsData, error: membershipsError } = await supabase .from('memberships') .select('user_id') .eq('club_id', userId); if (membershipsError) { console.error('Error fetching memberships:', membershipsError.message); toast.error("There was an error: Memberships Unavailable") return; } const emails = []; for (const member of membershipsData) { const { data: userDirectoryData, error: userDirectoryError } = await supabase .from('user_directory') .select('email') .eq('user_id', member.user_id); if (userDirectoryError) { console.error('Error fetching user directory:', userDirectoryError.message); toast.error("There was an error: User Directory Unavailable") continue; } for (const members of userDirectoryData) { emails.push({ schoolName: clubSchool, email: members.email, clubName: clubName, meetingDate: selectedDate?.toISOString(), meetingTime: `${startTime} - ${endTime}`, meetingDescription: meetingData.meeting_data.description, meetingName: meetingData.meeting_data.title, mandatory: meetingData.meeting_data.mandatory, clubCode: clubCode, location: meetingData.meeting_data.location, type: selectedType, meetingId: meetingData.meeting_id, }); } } // Send POST request to the endpoint const response = await fetch('/api/email/meetingNotification', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(emails), }); if (!response.ok) { console.error('Failed to send emails:'); toast.error("Notification System Error!") } else { console.log('Emails sent successfully'); router.push("/dashboard/club/meetings") } } else { console.log('Push notifications are disabled: Emails not sent!'); }
错误信息
Failed to send emails: TypeError: Cannot convert a Symbol value to a string at _ (/Users/musamalik/Downloads/[redacted]/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:254562) at Object.get (/Users/musamalik/Downloads/[redacted]/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:254683) at Proxy.toString (<anonymous>) at MeetingNotification (webpack-internal:///(rsc)/./emails/meetingNotification.tsx:319:93) at eval (webpack-internal:///(rsc)/./src/app/api/email/meetingNotification/route.ts:19:95) at Array.map (<anonymous>) at POST (webpack-internal:///(rsc)/./src/app/api/email/meetingNotification/route.ts:14:38) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async /Users/musamalik/Downloads/[redacted]/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:63251
排查思路与解决方案
从错误栈可以明确,问题出在MeetingNotification.tsx文件的第319行,该位置在执行字符串转换时遇到了Symbol类型的值。虽然你的API和调用代码中没有显式使用Symbol,但可能存在以下隐式场景:
1. 检查邮件组件的关键代码
直接查看MeetingNotification.tsx第319行的代码,确认此处是否在做字符串拼接、模板字符串渲染,或者将props值转换为字符串的操作。重点检查该位置用到的所有props变量(比如type、location、mandatory等),是否有变量被意外赋值为Symbol类型。
2. 对传入组件的props做安全转换
在API路由调用MeetingNotification前,强制将所有props转换为预期类型,避免Symbol或其他异常类型传入:
// 在map循环内,调用MeetingNotification前添加 const safeProps = { schoolName: String(schoolName), location: String(location), type: String(type), clubName: String(clubName), meetingDate: new Date(meetingDate).toDateString(), meetingId: String(meetingId), meetingTime: String(meetingTime), meetingDescription: String(meetingDescription), meetingName: String(meetingName), mandatory: Boolean(mandatory), }; // 用转换后的props调用组件 react: MeetingNotification(safeProps)
3. 校验前端传入的参数类型
检查sendMeetingNotification函数中构造emails数组时的变量(比如selectedType、clubSchool、startTime等),确认这些变量是否为字符串类型。如果某些变量来自第三方库或状态管理,可能被意外设置为Symbol。可以在构造数组时添加类型日志:
// 在emails.push前添加 console.log("Email item types:", { schoolName: typeof clubSchool, type: typeof selectedType, location: typeof meetingData.meeting_data.location });
4. 组件内部添加类型防护
在MeetingNotification组件中,对接收的props做类型断言或默认值处理,确保所有用到的变量都是可安全转换为字符串的类型:
interface MeetingNotificationProps { schoolName: string; location: string; type: string; // ...其他属性 } export default function MeetingNotification(props: MeetingNotificationProps) { // 给所有props设置默认值,避免undefined或异常类型 const { schoolName = "", location = "", type = "", // ...其他属性 } = props; // 组件渲染代码 }
内容的提问来源于stack exchange,提问作者Musa Malik

