@@ -31,7 +31,7 @@ import { resolveImageLoader } from "../core/resolve.js";
3131import {
3232 FatalError ,
3333 IgnorableError ,
34- RecoverableError ,
34+ type RecoverableError ,
3535} from "../utils/error.js" ;
3636import { debug , error } from "./logger.js" ;
3737import { optimizeImage } from "./plugins/image-optimization/image-optimization.js" ;
@@ -87,7 +87,8 @@ export async function defaultHandler(
8787 // We return a 400 here if imageParams returns an errorMessage
8888 // https://github.com/vercel/next.js/blob/512d8283054407ab92b2583ecce3b253c3be7b85/packages/next/src/server/next-server.ts#L937-L941
8989 if ( "errorMessage" in imageParams ) {
90- const clientError = new RecoverableError ( imageParams . errorMessage , 400 ) ;
90+ // Use IgnorableError for client-side validation issues (logLevel 0) to prevent monitoring alerts
91+ const clientError = new IgnorableError ( imageParams . errorMessage , 400 ) ;
9192 error ( "Error during validation of image params" , clientError ) ;
9293 return buildFailureResponse (
9394 imageParams . errorMessage ,
@@ -137,59 +138,48 @@ export async function defaultHandler(
137138//////////////////////
138139
139140/**
140- * Classifies an error and converts it to the appropriate OpenNext error type
141- * with the correct status code and logging level.
141+ * Classifies an error as either a client error (IgnorableError) or server error (FatalError)
142+ * to ensure proper logging behavior without triggering false monitoring alerts.
143+ *
144+ * The primary goal is to preserve the original error information while ensuring
145+ * client errors don't trigger monitoring alerts.
142146 */
143147function classifyError ( e : any ) : IgnorableError | RecoverableError | FatalError {
144- // Default values
145- let statusCode = 500 ;
146- const message = e ?. message || "Internal server error" ;
147-
148148 // If it's already an OpenNext error, return it directly
149149 if ( e && typeof e === "object" && "__openNextInternal" in e ) {
150150 return e ;
151151 }
152152
153- // Determine if this is a client error (4xx) or server error (5xx)
154- const isClientError =
153+ // Preserve the original message
154+ const message = e ?. message || "Internal server error" ;
155+
156+ // Preserve the original status code if available, otherwise use a default
157+ let statusCode = 500 ;
158+ if (
155159 e &&
156160 typeof e === "object" &&
157- ( ( "statusCode" in e &&
158- typeof e . statusCode === "number" &&
159- e . statusCode >= 400 &&
160- e . statusCode < 500 ) ||
161- e . code === "ENOTFOUND" ||
162- e . code === "ECONNREFUSED" ||
163- ( e . message &&
164- ( e . message . includes ( "403" ) ||
165- e . message . includes ( "404" ) ||
166- e . message . includes ( "Access Denied" ) ||
167- e . message . includes ( "Not Found" ) ) ) ) ;
168-
169- // Determine appropriate status code based on error type
170- if ( e && typeof e === "object" ) {
171- if ( "statusCode" in e && typeof e . statusCode === "number" ) {
172- statusCode = e . statusCode ;
173- } else if ( "code" in e ) {
174- const code = e . code as string ;
175- if ( code === "ENOTFOUND" || code === "ECONNREFUSED" ) {
176- statusCode = 404 ;
177- }
178- } else if ( e . message ) {
179- if ( e . message . includes ( "403" ) || e . message . includes ( "Access Denied" ) ) {
180- statusCode = 403 ;
181- } else if ( e . message . includes ( "404" ) || e . message . includes ( "Not Found" ) ) {
182- statusCode = 404 ;
183- }
184- }
161+ "statusCode" in e &&
162+ typeof e . statusCode === "number"
163+ ) {
164+ statusCode = e . statusCode ;
185165 }
186166
187- // Client errors (4xx) are wrapped as IgnorableError to prevent noise in monitoring
188- if ( isClientError || statusCode < 500 ) {
167+ // Simple check for client errors - anything with a 4xx status code
168+ // or common error codes that indicate client issues
169+ const isClientError =
170+ ( statusCode >= 400 && statusCode < 500 ) ||
171+ ( e &&
172+ typeof e === "object" &&
173+ ( e . code === "ENOTFOUND" ||
174+ e . code === "ECONNREFUSED" ||
175+ e . code === "ETIMEDOUT" ) ) ;
176+
177+ // Wrap client errors as IgnorableError to prevent monitoring alerts
178+ if ( isClientError ) {
189179 return new IgnorableError ( message , statusCode ) ;
190180 }
191181
192- // Server errors (5xx) are marked as FatalError to ensure proper monitoring
182+ // Server errors are marked as FatalError to ensure proper monitoring
193183 return new FatalError ( message , statusCode ) ;
194184}
195185
@@ -413,49 +403,16 @@ async function downloadHandler(
413403 }
414404 }
415405 } catch ( e : any ) {
416- // Check if this is a client error (like 404, 403, etc.)
417- const isClientError =
418- e &&
419- typeof e === "object" &&
420- ( ( "statusCode" in e &&
421- typeof e . statusCode === "number" &&
422- e . statusCode >= 400 &&
423- e . statusCode < 500 ) ||
424- e . code === "ENOTFOUND" ||
425- e . code === "ECONNREFUSED" ||
426- ( e . message &&
427- ( e . message . includes ( "403" ) ||
428- e . message . includes ( "404" ) ||
429- e . message . includes ( "Access Denied" ) ||
430- e . message . includes ( "Not Found" ) ) ) ) ;
431-
432- if ( isClientError ) {
433- debug ( "Client error downloading image" , e ) ;
434- // Just pass through the original error to preserve Next.js's error handling
435- // but wrap it in IgnorableError to prevent it from being logged as an error
436- const clientError = new IgnorableError (
437- e . message || "Client error downloading image" ,
438- ) ;
439-
440- // Preserve the original status code or set an appropriate one
441- if ( e && typeof e === "object" ) {
442- if ( "statusCode" in e && typeof e . statusCode === "number" ) {
443- ( clientError as any ) . statusCode = e . statusCode ;
444- } else if ( e . code === "ENOTFOUND" || e . code === "ECONNREFUSED" ) {
445- ( clientError as any ) . statusCode = 404 ;
446- } else if ( e . message ?. includes ( "403" ) ) {
447- ( clientError as any ) . statusCode = 403 ;
448- } else if ( e . message ?. includes ( "404" ) ) {
449- ( clientError as any ) . statusCode = 404 ;
450- } else {
451- ( clientError as any ) . statusCode = 400 ;
452- }
453- }
406+ // Use our centralized error classification function
407+ const classifiedError = classifyError ( e ) ;
454408
455- throw clientError ;
456- }
409+ // Log error with appropriate level based on error type
410+ // This will automatically downgrade client errors to debug level
411+ error ( "Failed to download image" , classifiedError ) ;
457412
458- error ( "Failed to download image" , e ) ;
459- throw e ;
413+ // Since we're in a middleware (adapter) called by Next.js's image optimizer,
414+ // we should throw the properly classified error to let Next.js handle it appropriately
415+ // The Next.js image optimizer will use the status code and normalize the error message
416+ throw classifiedError ;
460417 }
461418}
0 commit comments