@@ -28,7 +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" ; 
31+ import  {  FatalError ,   IgnorableError  }  from  "../utils/error.js" ; 
3232import  {  debug ,  error  }  from  "./logger.js" ; 
3333import  {  optimizeImage  }  from  "./plugins/image-optimization/image-optimization.js" ; 
3434import  {  setNodeEnv  }  from  "./util.js" ; 
@@ -258,39 +258,18 @@ async function downloadHandler(
258258    res : ServerResponse , 
259259    isInternalImage : boolean , 
260260  )  { 
261-     let  originalStatus  =  e . statusCode  ||  e . $metadata ?. httpStatusCode  ||  500 ; 
262-     let  message  =  e . message  ||  "Failed to process image request" ; 
263- 
264-     // Special handling for S3 ListBucket permission errors 
265-     // AWS SDK v3 nests error details deeply within the error object 
266-     const  isListBucketError  = 
267-       ( message . includes ( "s3:ListBucket" )  &&  message . includes ( "AccessDenied" ) )  || 
268-       e . error ?. message ?. includes ( "s3:ListBucket" )  || 
269-       ( e . Code  ===  "AccessDenied"  &&  e . Message ?. includes ( "s3:ListBucket" ) ) ; 
270- 
271-     if  ( isListBucketError )  { 
272-       message  =  "Image not found or access denied" ; 
273-       // For S3 ListBucket errors, ensure we're using 403 (the actual AWS error) 
274-       if  ( originalStatus  ===  500  &&  e . $metadata ?. httpStatusCode  ===  403 )  { 
275-         originalStatus  =  403 ; 
276-       } 
261+     const  originalStatus  =  e . statusCode  ||  e . $metadata ?. httpStatusCode  ||  500 ; 
262+     const  message  =  e . message  ||  "Failed to process image request" ; 
277263
278-       // Log using IgnorableError to classify as client error 
279-       const  clientError  =  new  IgnorableError ( message ,  originalStatus ) ; 
280-       error ( "S3 ListBucket permission error" ,  clientError ) ; 
281-     }  else  { 
282-       // Log all other errors as client errors 
283-       const  clientError  =  new  IgnorableError ( message ,  originalStatus ) ; 
284-       error ( "Failed to process image" ,  clientError ) ; 
285-     } 
264+     // Log all other errors as client errors 
265+     const  clientError  =  new  IgnorableError ( message ,  originalStatus ) ; 
266+     error ( "Failed to process image" ,  clientError ) ; 
286267
287-     // For external images,  throw if not ListBucket error  
268+     // For external images we  throw with the status code  
288269    // Next.js will preserve the status code for external images 
289-     if  ( ! isInternalImage  &&  ! isListBucketError )  { 
290-       const  formattedError  =  new  Error ( message ) ; 
291-       // @ts -ignore: Add statusCode property to Error 
292-       formattedError . statusCode  =  originalStatus  >=  500  ? 400  : originalStatus ; 
293-       throw  formattedError ; 
270+     if  ( ! isInternalImage )  { 
271+       const  statusCode  =  originalStatus  >=  500  ? 400  : originalStatus ; 
272+       throw  new  FatalError ( message ,  statusCode ) ; 
294273    } 
295274
296275    // Different handling for internal vs external images 
@@ -303,18 +282,15 @@ async function downloadHandler(
303282      // This should result in "url parameter is valid but internal response is invalid" 
304283
305284      // Still include error details in headers for debugging only 
306-       const  errorMessage  =  isListBucketError  ? "Access denied"  : message ; 
307-       res . setHeader ( "x-nextjs-internal-error" ,  errorMessage ) ; 
285+       res . setHeader ( "x-nextjs-internal-error" ,  message ) ; 
308286      res . end ( ) ; 
309287    }  else  { 
310288      // For external images, maintain existing behavior with text/plain 
311289      res . setHeader ( "Content-Type" ,  "text/plain" ) ; 
312290
313-       if  ( isListBucketError )  { 
314-         res . end ( "Access denied" ) ; 
315-       }  else  { 
316-         res . end ( message ) ; 
317-       } 
291+       // We should **never** send the error message to the client 
292+       // This is to prevent leaking sensitive information 
293+       res . end ( "Failed to process image request" ) ; 
318294    } 
319295  } 
320296
0 commit comments