mirror of
https://github.com/DayuanJiang/next-ai-draw-io.git
synced 2026-01-02 14:22:28 +08:00
* feat: Show detailed error messages instead of generic 'Internal server error' (#144) * refactor: simplify error handling logic per feedback * refactor: imported AI SDK error handler * fix: remove unused import and expand sensitive data filter - Remove unused NoSuchModelError import - Add 'secret', 'password', 'credential' to sensitive data filter --------- Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import {
|
||||
APICallError,
|
||||
convertToModelMessages,
|
||||
createUIMessageStream,
|
||||
createUIMessageStreamResponse,
|
||||
LoadAPIKeyError,
|
||||
stepCountIs,
|
||||
streamText,
|
||||
} from "ai"
|
||||
@@ -451,16 +453,74 @@ IMPORTANT: Keep edits concise:
|
||||
})
|
||||
}
|
||||
|
||||
// Helper to categorize errors and return appropriate response
|
||||
function handleError(error: unknown): Response {
|
||||
console.error("Error in chat route:", error)
|
||||
|
||||
const isDev = process.env.NODE_ENV === "development"
|
||||
|
||||
// Check for specific AI SDK error types
|
||||
if (APICallError.isInstance(error)) {
|
||||
return Response.json(
|
||||
{
|
||||
error: error.message,
|
||||
...(isDev && {
|
||||
details: error.responseBody,
|
||||
stack: error.stack,
|
||||
}),
|
||||
},
|
||||
{ status: error.statusCode || 500 },
|
||||
)
|
||||
}
|
||||
|
||||
if (LoadAPIKeyError.isInstance(error)) {
|
||||
return Response.json(
|
||||
{
|
||||
error: "Authentication failed. Please check your API key.",
|
||||
...(isDev && {
|
||||
stack: error.stack,
|
||||
}),
|
||||
},
|
||||
{ status: 401 },
|
||||
)
|
||||
}
|
||||
|
||||
// Fallback for other errors with safety filter
|
||||
const message =
|
||||
error instanceof Error ? error.message : "An unexpected error occurred"
|
||||
const status = (error as any)?.statusCode || (error as any)?.status || 500
|
||||
|
||||
// Prevent leaking API keys, tokens, or other sensitive data
|
||||
const lowerMessage = message.toLowerCase()
|
||||
const safeMessage =
|
||||
lowerMessage.includes("key") ||
|
||||
lowerMessage.includes("token") ||
|
||||
lowerMessage.includes("sig") ||
|
||||
lowerMessage.includes("signature") ||
|
||||
lowerMessage.includes("secret") ||
|
||||
lowerMessage.includes("password") ||
|
||||
lowerMessage.includes("credential")
|
||||
? "Authentication failed. Please check your credentials."
|
||||
: message
|
||||
|
||||
return Response.json(
|
||||
{
|
||||
error: safeMessage,
|
||||
...(isDev && {
|
||||
details: message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
}),
|
||||
},
|
||||
{ status },
|
||||
)
|
||||
}
|
||||
|
||||
// Wrap handler with error handling
|
||||
async function safeHandler(req: Request): Promise<Response> {
|
||||
try {
|
||||
return await handleChatRequest(req)
|
||||
} catch (error) {
|
||||
console.error("Error in chat route:", error)
|
||||
return Response.json(
|
||||
{ error: "Internal server error" },
|
||||
{ status: 500 },
|
||||
)
|
||||
return handleError(error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -462,13 +462,23 @@ Please retry with an adjusted search pattern or use display_diagram if retries a
|
||||
console.error("Chat error:", error)
|
||||
}
|
||||
|
||||
// Translate technical errors into user-friendly messages
|
||||
// The server now handles detailed error messages, so we can display them directly.
|
||||
// But we still handle connection/network errors that happen before reaching the server.
|
||||
let friendlyMessage = error.message
|
||||
|
||||
// Simple check for network errors if message is generic
|
||||
if (friendlyMessage === "Failed to fetch") {
|
||||
friendlyMessage = "Network error. Please check your connection."
|
||||
}
|
||||
|
||||
// Add system message for error so it can be cleared
|
||||
setMessages((currentMessages) => {
|
||||
const errorMessage = {
|
||||
id: `error-${Date.now()}`,
|
||||
role: "system" as const,
|
||||
content: error.message,
|
||||
parts: [{ type: "text" as const, text: error.message }],
|
||||
content: friendlyMessage,
|
||||
parts: [{ type: "text" as const, text: friendlyMessage }],
|
||||
}
|
||||
return [...currentMessages, errorMessage]
|
||||
})
|
||||
|
||||
24
package-lock.json
generated
24
package-lock.json
generated
@@ -1120,6 +1120,7 @@
|
||||
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.27.1",
|
||||
"@babel/generator": "^7.28.5",
|
||||
@@ -1606,6 +1607,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
@@ -1628,6 +1630,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -2735,6 +2738,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz",
|
||||
"integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
@@ -2768,6 +2772,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.2.0.tgz",
|
||||
"integrity": "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@opentelemetry/semantic-conventions": "^1.29.0"
|
||||
},
|
||||
@@ -2783,6 +2788,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.208.0.tgz",
|
||||
"integrity": "sha512-jbzDw1q+BkwKFq9yxhjAJ9rjKldbt5AgIy1gmEIJjEV/WRxQ3B6HcLVkwbjJ3RcMif86BDNKR846KJ0tY0aOJA==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@opentelemetry/core": "2.2.0",
|
||||
"@opentelemetry/otlp-exporter-base": "0.208.0",
|
||||
@@ -2888,6 +2894,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.2.0.tgz",
|
||||
"integrity": "sha512-xWQgL0Bmctsalg6PaXExmzdedSp3gyKV8mQBwK/j9VGdCDu2fmXIb2gAehBKbkXCpJ4HPkgv3QfoJWRT4dHWbw==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@opentelemetry/core": "2.2.0",
|
||||
"@opentelemetry/resources": "2.2.0",
|
||||
@@ -5294,6 +5301,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.0.tgz",
|
||||
"integrity": "sha512-UaicktuQI+9UKyA4njtDOGBD/67t8YEBt2xdfqu8+gP9hqPUPsiXlNPcpS2gVdjmis5GKPG3fCxbQLVgxsQZ8w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
@@ -5304,6 +5312,7 @@
|
||||
"integrity": "sha512-jFf/woGTVTjUJsl2O7hcopJ1r0upqoq/vIOoCj0yLh3RIXxWcljlpuZ+vEBRXsymD1jhfeJrlyTy/S1UW+4y1w==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"@types/react": "^19.0.0"
|
||||
}
|
||||
@@ -5360,6 +5369,7 @@
|
||||
"integrity": "sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.48.0",
|
||||
"@typescript-eslint/types": "8.48.0",
|
||||
@@ -5908,6 +5918,7 @@
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -5939,6 +5950,7 @@
|
||||
"resolved": "https://registry.npmjs.org/ai/-/ai-5.0.107.tgz",
|
||||
"integrity": "sha512-laZlS9ZC/DZfSaxPgrBqI4mM+kxRvTPBBQfa74ceBFskkunZKEsaGVFNEs4cfyGa3nCCCl1WO/fjxixp4V8Zag==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@ai-sdk/gateway": "2.0.18",
|
||||
"@ai-sdk/provider": "2.0.0",
|
||||
@@ -6371,6 +6383,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.8.25",
|
||||
"caniuse-lite": "^1.0.30001754",
|
||||
@@ -7192,6 +7205,7 @@
|
||||
"integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.8.0",
|
||||
"@eslint-community/regexpp": "^4.12.1",
|
||||
@@ -7377,6 +7391,7 @@
|
||||
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@rtsao/scc": "^1.1.0",
|
||||
"array-includes": "^3.1.9",
|
||||
@@ -10430,6 +10445,7 @@
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-16.0.7.tgz",
|
||||
"integrity": "sha512-3mBRJyPxT4LOxAJI6IsXeFtKfiJUbjCLgvXO02fV8Wy/lIhPvP94Fe7dGhUgHXcQy4sSuYwQNcOLhIfOm0rL0A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@next/env": "16.0.7",
|
||||
"@swc/helpers": "0.5.15",
|
||||
@@ -11013,6 +11029,7 @@
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
|
||||
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -11022,6 +11039,7 @@
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
|
||||
"integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"scheduler": "^0.26.0"
|
||||
},
|
||||
@@ -12059,7 +12077,8 @@
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.2.tgz",
|
||||
"integrity": "sha512-VCsK+fitIbQF7JlxXaibFhxrPq4E2hDcG8apzHUdWFMCQWD8uLdlHg4iSkZ53cgLCCcZ+FZK7vG8VjvLcnBgKw==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/tailwindcss-animate": {
|
||||
"version": "1.0.7",
|
||||
@@ -12146,6 +12165,7 @@
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -12370,6 +12390,7 @@
|
||||
"integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -12980,6 +13001,7 @@
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz",
|
||||
"integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user