The documentation page includes an example of a handler that throws a custom error to replace the original error. This example does not work and any error you throw from within a handler will leak (unless you have an unhandledRejection
listener to do something with it).
I tested this with a handler that is pretty much identical to the recommendation in the docs:
const got = Got.extend( { handlers : [
( options, next ) => {
return ( async () => {
try {
return await next( options );
} catch ( error ) {
throw new Error( 'Replacement Error' );
}
} )();
},
] } );
await got( `https://httpstat.us/404` ).json();
Throwing an error from a handler leaks a promise that will be rejected with the new error, and has no effect on the result of the request. If the actual HTTP request was successful then the got request will be resolved successfully, ignoring the error that was thrown in the handler. If the actual HTTP request was unsuccessful then any error you throw from the handler will again be ignored, and the got request will be resolved with whatever the original failure was.
Running the script included below produces this:
Attempting to replace error
[FAIL] Got wrong error: Response code 404 (Not Found)
[FAIL] Got unhandled rejection: Replacement Error
Throwing error on successful request
[FAIL] Did not expect a successful response
[FAIL] Got unhandled rejection: Async Error
Throwing an error from a handler causes the request to be rejected with that error.
I expected that the script below would produce this:
Attempting to replace error
[PASS] Got correct error
Throwing error on successful request
[PASS] Got correct error
Here is a more complete and runnable test script
#!/usr/bin/env node
import Got from 'got';
process.on( 'unhandledRejection', err => {
console.log( `[FAIL] Got unhandled rejection: ${err.message}` );
} );
async function replaceError() {
try {
const got = Got.extend( { handlers : [
( options, next ) => {
return ( async () => {
try {
return await next( options );
} catch ( error ) {
throw new Error( 'Replacement Error' );
}
} )();
},
] } );
return await got( `https://httpstat.us/404` ).json();
} catch ( err ) {
if ( err.message === 'Replacement Error' ) {
console.log( '[PASS] Got correct error' );
} else {
console.log( '[FAIL] Got wrong error:', err.message );
}
}
}
async function throwOnSuccessfulRequest() {
try {
const got = Got.extend( { handlers : [
( options, next ) => {
return ( async () => {
await next( options );
throw new Error( 'Async Error' );
} )();
},
] } );
await got( `https://httpstat.us/200` ).json();
console.log( '[FAIL] Did not expect a successful response' );
} catch ( err ) {
if ( err.message === 'Async Error' ) {
console.log( '[PASS] Got correct error' );
} else {
console.log( '[FAIL] Got wrong error:', err.message );
}
}
}
// This interval just makes sure that node keeps the script running
// until all the promises are resolved.
const interval = setInterval( () => {}, 1000 );
console.log( 'Attempting to replace error' );
await replaceError();
// This is just to make sure that the unhandled rejection is detected
// before we move on to the next test
await new Promise( resolve => setTimeout( resolve, 1000 ) );
console.log( '\nThrowing error on successful request' );
await throwOnSuccessfulRequest();
clearInterval( interval );
Pay now to fund the work behind this issue.
Get updates on progress being made.
Maintainer is rewarded once the issue is completed.
You're funding impactful open source efforts
You want to contribute to this effort
You want to get funding like this too