@@ -28,6 +28,7 @@ import { emptyReadableStream, toReadableStream } from "utils/stream.js";
2828import type { OpenNextHandlerOptions } from "types/overrides.js" ;
2929import { createGenericHandler } from "../core/createGenericHandler.js" ;
3030import { resolveImageLoader } from "../core/resolve.js" ;
31+ import { IgnorableError } from "../utils/error.js" ;
3132import { debug , error } from "./logger.js" ;
3233import { optimizeImage } from "./plugins/image-optimization/image-optimization.js" ;
3334import { setNodeEnv } from "./util.js" ;
@@ -114,44 +115,54 @@ export async function defaultHandler(
114115 ) ;
115116 return buildSuccessResponse ( result , options ?. streamCreator , etag ) ;
116117 } catch ( e : any ) {
117- error ( "Failed to optimize image" , e ) ;
118-
119- // Determine appropriate status code based on error
118+ // Determine if this is a client error (4xx) or server error (5xx)
120119 let statusCode = 500 ; // Default to 500 for unknown errors
121- let errorMessage = "Internal server error" ;
120+ const isClientError =
121+ e &&
122+ typeof e === "object" &&
123+ ( ( "statusCode" in e &&
124+ typeof e . statusCode === "number" &&
125+ e . statusCode >= 400 &&
126+ e . statusCode < 500 ) ||
127+ e . code === "ENOTFOUND" ||
128+ e . code === "ECONNREFUSED" ||
129+ ( e . message &&
130+ ( e . message . includes ( "403" ) ||
131+ e . message . includes ( "404" ) ||
132+ e . message . includes ( "Access Denied" ) ||
133+ e . message . includes ( "Not Found" ) ) ) ) ;
134+
135+ // Only log actual server errors as errors, log client errors as debug
136+ if ( isClientError ) {
137+ debug ( "Client error in image optimization" , e ) ;
138+ } else {
139+ error ( "Failed to optimize image" , e ) ;
140+ }
122141
123- // Check if error has HTTP status information
142+ // Determine appropriate status code based on error type
124143 if ( e && typeof e === "object" ) {
125144 if ( "statusCode" in e && typeof e . statusCode === "number" ) {
126145 statusCode = e . statusCode ;
127- errorMessage = `HTTP Error: ${ statusCode } ` ;
128146 } else if ( "code" in e ) {
129147 const code = e . code as string ;
130148 if ( code === "ENOTFOUND" || code === "ECONNREFUSED" ) {
131149 statusCode = 404 ;
132- errorMessage = `Image not found: ${ e . message } ` ;
133150 }
134- }
135-
136- if ( e . message && typeof e . message === "string" ) {
137- // Try to extract status codes from error messages
151+ } else if ( e . message ) {
138152 if ( e . message . includes ( "403" ) || e . message . includes ( "Access Denied" ) ) {
139153 statusCode = 403 ;
140- errorMessage = `Access denied: ${ e . message } ` ;
141154 } else if (
142155 e . message . includes ( "404" ) ||
143156 e . message . includes ( "Not Found" )
144157 ) {
145158 statusCode = 404 ;
146- errorMessage = `Image not found: ${ e . message } ` ;
147- } else {
148- errorMessage = e . message ;
149159 }
150160 }
151161 }
152162
163+ // Pass through the original error message from Next.js
153164 return buildFailureResponse (
154- errorMessage ,
165+ e . message || "Internal server error" ,
155166 options ?. streamCreator ,
156167 statusCode ,
157168 ) ;
@@ -318,18 +329,25 @@ async function downloadHandler(
318329 } ) ;
319330 } ) ;
320331
321- request . on ( "error" , ( err : NodeJS . ErrnoException ) => {
322- error ( "Failed to get image" , err ) ;
323- // Handle common network errors
324- if ( err && typeof err === "object" && "code" in err ) {
325- if ( err . code === "ENOTFOUND" || err . code === "ECONNREFUSED" ) {
326- res . statusCode = 404 ;
327- } else {
328- res . statusCode = 400 ;
329- }
332+ request . on ( "error" , ( err : Error & { code ?: string } ) => {
333+ // For network errors, these are typically client errors (bad URL, etc.)
334+ // so log as debug instead of error to avoid false alarms
335+ const isClientError =
336+ err . code === "ENOTFOUND" || err . code === "ECONNREFUSED" ;
337+
338+ if ( isClientError ) {
339+ // Log the full error for debugging but don't expose it to the client
340+ debug ( "Client error fetching image" , {
341+ code : err . code ,
342+ message : err . message ,
343+ } ) ;
344+ res . statusCode = 404 ; // Not Found for DNS or connection errors
330345 } else {
331- res . statusCode = 400 ;
346+ error ( "Failed to get image" , err ) ;
347+ res . statusCode = 400 ; // Bad Request for other errors
332348 }
349+
350+ // Don't send the error message back to the client
333351 res . end ( ) ;
334352 } ) ;
335353 }
@@ -357,6 +375,48 @@ async function downloadHandler(
357375 }
358376 }
359377 } catch ( e : any ) {
378+ // Check if this is a client error (like 404, 403, etc.)
379+ const isClientError =
380+ e &&
381+ typeof e === "object" &&
382+ ( ( "statusCode" in e &&
383+ typeof e . statusCode === "number" &&
384+ e . statusCode >= 400 &&
385+ e . statusCode < 500 ) ||
386+ e . code === "ENOTFOUND" ||
387+ e . code === "ECONNREFUSED" ||
388+ ( e . message &&
389+ ( e . message . includes ( "403" ) ||
390+ e . message . includes ( "404" ) ||
391+ e . message . includes ( "Access Denied" ) ||
392+ e . message . includes ( "Not Found" ) ) ) ) ;
393+
394+ if ( isClientError ) {
395+ debug ( "Client error downloading image" , e ) ;
396+ // Just pass through the original error to preserve Next.js's error handling
397+ // but wrap it in IgnorableError to prevent it from being logged as an error
398+ const clientError = new IgnorableError (
399+ e . message || "Client error downloading image" ,
400+ ) ;
401+
402+ // Preserve the original status code or set an appropriate one
403+ if ( e && typeof e === "object" ) {
404+ if ( "statusCode" in e && typeof e . statusCode === "number" ) {
405+ ( clientError as any ) . statusCode = e . statusCode ;
406+ } else if ( e . code === "ENOTFOUND" || e . code === "ECONNREFUSED" ) {
407+ ( clientError as any ) . statusCode = 404 ;
408+ } else if ( e . message ?. includes ( "403" ) ) {
409+ ( clientError as any ) . statusCode = 403 ;
410+ } else if ( e . message ?. includes ( "404" ) ) {
411+ ( clientError as any ) . statusCode = 404 ;
412+ } else {
413+ ( clientError as any ) . statusCode = 400 ;
414+ }
415+ }
416+
417+ throw clientError ;
418+ }
419+
360420 error ( "Failed to download image" , e ) ;
361421 throw e ;
362422 }
0 commit comments