@@ -28,6 +28,7 @@ import { emptyReadableStream, toReadableStream } from "utils/stream.js";
28
28
import type { OpenNextHandlerOptions } from "types/overrides.js" ;
29
29
import { createGenericHandler } from "../core/createGenericHandler.js" ;
30
30
import { resolveImageLoader } from "../core/resolve.js" ;
31
+ import { IgnorableError } from "../utils/error.js" ;
31
32
import { debug , error } from "./logger.js" ;
32
33
import { optimizeImage } from "./plugins/image-optimization/image-optimization.js" ;
33
34
import { setNodeEnv } from "./util.js" ;
@@ -114,44 +115,54 @@ export async function defaultHandler(
114
115
) ;
115
116
return buildSuccessResponse ( result , options ?. streamCreator , etag ) ;
116
117
} 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)
120
119
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
+ }
122
141
123
- // Check if error has HTTP status information
142
+ // Determine appropriate status code based on error type
124
143
if ( e && typeof e === "object" ) {
125
144
if ( "statusCode" in e && typeof e . statusCode === "number" ) {
126
145
statusCode = e . statusCode ;
127
- errorMessage = `HTTP Error: ${ statusCode } ` ;
128
146
} else if ( "code" in e ) {
129
147
const code = e . code as string ;
130
148
if ( code === "ENOTFOUND" || code === "ECONNREFUSED" ) {
131
149
statusCode = 404 ;
132
- errorMessage = `Image not found: ${ e . message } ` ;
133
150
}
134
- }
135
-
136
- if ( e . message && typeof e . message === "string" ) {
137
- // Try to extract status codes from error messages
151
+ } else if ( e . message ) {
138
152
if ( e . message . includes ( "403" ) || e . message . includes ( "Access Denied" ) ) {
139
153
statusCode = 403 ;
140
- errorMessage = `Access denied: ${ e . message } ` ;
141
154
} else if (
142
155
e . message . includes ( "404" ) ||
143
156
e . message . includes ( "Not Found" )
144
157
) {
145
158
statusCode = 404 ;
146
- errorMessage = `Image not found: ${ e . message } ` ;
147
- } else {
148
- errorMessage = e . message ;
149
159
}
150
160
}
151
161
}
152
162
163
+ // Pass through the original error message from Next.js
153
164
return buildFailureResponse (
154
- errorMessage ,
165
+ e . message || "Internal server error" ,
155
166
options ?. streamCreator ,
156
167
statusCode ,
157
168
) ;
@@ -318,18 +329,25 @@ async function downloadHandler(
318
329
} ) ;
319
330
} ) ;
320
331
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
330
345
} else {
331
- res . statusCode = 400 ;
346
+ error ( "Failed to get image" , err ) ;
347
+ res . statusCode = 400 ; // Bad Request for other errors
332
348
}
349
+
350
+ // Don't send the error message back to the client
333
351
res . end ( ) ;
334
352
} ) ;
335
353
}
@@ -357,6 +375,48 @@ async function downloadHandler(
357
375
}
358
376
}
359
377
} 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
+
360
420
error ( "Failed to download image" , e ) ;
361
421
throw e ;
362
422
}
0 commit comments