New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve axios stack traces #2387
Comments
This makes it super hard to debug bad responses from other servers when you are making lots of calls. |
Maybe axios can use https://stackoverflow.com/a/42755876 |
@jmicco I don't understand why this makes it super hard to debug. |
Hi Waris,
Stack traces for async functions in Node are difficult to deal with and
adding catch / rethrow into code to tease out the stack trace does not seem
practical. When we get a trace from Axios our code is never listed on the
stack making it hard to understand where we got the problem. We are
calling several different other micro-services and it is not clear which
call received an error. It would be very convenient if code were added to
axios to improve the stack traces that get thrown for all consumers exactly
once - although I do understand that this is more of a NodeJS asynchronous
function problem and it is not really axios specific.
Thanks for listening!
Cheers,
John
…On Mon, Dec 2, 2019 at 4:18 AM WarisR ***@***.***> wrote:
@jmicco <https://github.com/jmicco> I don't understand why this makes it
super hard to debug.
Is it still super hard if I use this pattern?
https://stackoverflow.com/a/42755876 (merge stacktrace)
Could you please give me more example? Thank you.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#2387?email_source=notifications&email_token=ABSTB6E6HYKQUZVB4JVEYBTQWT4HVA5CNFSM4ITJ3JL2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEFTJUBQ#issuecomment-560372230>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABSTB6FJ4NIZ3VHRBCH7JCTQWT4HVANCNFSM4ITJ3JLQ>
.
|
Hi @jmicco It seems the problem is axios discard original error and create new error instead of reusing original error (with original stack trace). Please correct me if i'm wrong. Edit: nodejs already support async stack trace: https://thecodebarbarian.com/async-stack-traces-in-node-js-12 |
Bump up. Turning on async stacktraces on newest node does not help. |
Another way is implement a new option for customize error message, eg.: axios({
method: 'get',
url: 'http://bit.ly/2mTM3nY',
customErrorMessage: (response) => 'Request at URL '+ response.config.url +' failed with status code ' + response.status
})
.then(response=> console.log(response))
.catch(error => console.log(error)); this just require a minimal implementation in https://github.com/axios/axios/blob/master/lib/core/settle.js 'use strict';
var createError = require('./createError');
/**
* Resolve or reject a Promise based on response status.
*
* @param {Function} resolve A function that resolves the promise.
* @param {Function} reject A function that rejects the promise.
* @param {object} response The response.
*/
module.exports = function settle(resolve, reject, response) {
var validateStatus = response.config.validateStatus;
if (!validateStatus || validateStatus(response.status)) {
resolve(response);
} else {
var customErrorMessage = response.config.customErrorMessage;
var message = customErrorMessage ? customErrorMessage(response) : 'Request failed with status code ' + response.status;
reject(createError(
message,
response.config,
null,
response.request,
response
));
}
}; |
In case anyone needs a solution for this, I have managed to solve the stack trace problem storing the current stack trace in a variable and replacing it before throwing the error: const { stack } = new Error();
return instance.get(endpoint, { params, ...config }).catch(error => {
error.stack = stackTrace;
throw error;
}); I explained everything here: rafaelalmeidatk/TIL#4 |
no updates regarding this issue ? |
I've managed to work around this issue by using interceptors. I create an Error in a request interceptor, store it on a config property, then use its stack trace in the response interceptor's error handler. This is obviously less than ideal and it would be better to not clobber the stack trace in the first place. const client = axios.create();
client.interceptors.request.use(config => {
config.errorContext = new Error("Thrown at:");
return config;
});
client.interceptors.response.use(undefined, async error => {
const originalStackTrace = error.config?.errorContext?.stack;
if (originalStackTrace) {
error.stack = `${error.stack}\n${originalStackTrace}`;
}
throw error;
}); This results in pretty reasonable stack traces:
|
As a personal rule of thumb, due to this issue I always use
and handle the |
The interceptors' approach proposed by @jekh for some reason was not showing the exact method that initiated a request for me, but I managed to get a similar stack trace by patching |
This worked perfectly for us. Thank you @svsool! |
Some updates in this??? |
Please use the interceptor approach mentioned above, we will address this in the future however currently an interceptor is the most appropriate solution. |
I have replaced native Promises with Bluebird in my application. Bluebird supports long stack traces and I now have decent stack traces across async boundaries, including calls to axios methods. |
Hi @jasonsaayman, I see this issue brings lots of headaches and a bad developer experience to those who fall into these scenarios without any knowledge about the need of such interceptor. I don't think that's the best solution and imho, it degrades Axios as a good library for production-ready applications. A fix should be as easy as implementing something like Lines 16 to 17 in 5bc9ea2
to var axiosError = enhanceError(new Error(message), config, code, request, response);
if (Error.captureStackTrace) Error.captureStackTrace(axiosError, createError);
return axiosError; Yes, it MAY degrade performance (imo its negligible) for failing requests, but we all know this is better than having no input for proper debugging. I can open a PR with this and discuss the approach if you want. |
@Frondor yes PR please |
Hi all, for me neither interceptors not axios-better-stacktrace package didn't help. Once it enters into an interceptor it looses all stack trace.
And this is what I see in my first interceptor
|
I'm running into an issue where @jekh's solution isn't working for me. I've defined both of the interceptors as suggested. In addition, we're adding a correlation ID to every request, e.g. client.interceptors.request.use((config) => {
config.headers["x-correlation-id"] = correlator.getId();
return config;
}); I'm currently debugging an issue where
I'm guessing because the header isn't set, somehow the error handling is different, and the I did find a workaround: our axios client is actually in a class, so in reality the first interceptor looks more like this: this.client.interceptors.request.use((config) => {
config.errorContext = new Error("Thrown at:");
return config;
}); Since the config ends up being empty in the request interceptor error handler, I just save the error context as a class variable instead, e.g. this.client.interceptors.request.use((config) => {
this.errorContext = new Error("Thrown at:");
return config;
});
this.client.interceptors.response.use(undefined, async (error) => {
if (this.errorContext?.stack) {
error.stack = `${error.stack}\n${this.errorContext.stack}`;
}
throw error;
}); And now I have the error context once again:
|
How did you do this in a way that Axios then uses Bluebird promises? |
@jasonsaayman I didnt see any PRs from the original commenter and I'm happy to complete this. Is this still relevant? |
You can for sure, please check master we made a whole load of changes to the way errors work for the next release |
Related to discussions here axios#2387 Attempt to capture the stack trace at the time the error is created in order to maintain context about where the error originates from.
Related to discussions here #2387 Attempt to capture the stack trace at the time the error is created in order to maintain context about where the error originates from. Co-authored-by: Jay <jasonsaayman@gmail.com>
Did @despreston's pull request (which was an implementation of @Frondor's suggestion) actually fix the problem? I'm running Node v18.16.0 and axios v1.4.0 and still getting stacktraces like what @rclmenezes was seeing at the beginning of this issue. |
Hello 'Doron,
Thank you for contacting us! The Notable office is currently closed in observance of the Memorial Day Holiday.
We will resume normal business hours on Tuesday, May 30th from 9am to 9pm EST and look forward to assisting you at that time.
Best Regards,
The Notable Team
|
Related to discussions here axios/axios#2387 Attempt to capture the stack trace at the time the error is created in order to maintain context about where the error originates from. Co-authored-by: Jay <jasonsaayman@gmail.com>
Same for me running same versions of Node and axios. When making identical requests made with fetch gives me the stack trace I need but with axios 1.4.0 I only get the library stack. Stack trace: Error: getaddrinfo ENOTFOUND sonplaceholder.typicode.com |
will have a look |
@jasonsaayman Were you possibly able to confirm @despreston's change? Does |
@jedkass for me the stack traces are still quite useless. At least in Sentry with Axios v1.5.0. I am running Node.js v20.7.0. |
Ah that's a shame. @jasonsaayman Shouldn't we reopen this issue in that case? Or is this being tracked elsewhere? |
reopening, that sucks |
I also ran into this issue and was able to get more usable stack traces by applying this patch to axios@1.5.0:
The same patch could be applied to lib/core/Axios.js if you're using ESM. After applying that patch and running this script: const axios = require('axios');
async function makeRequest() {
await axios.get('https://httpstat.us/500');
}
async function main() {
await makeRequest();
}
main().catch((err) => {
console.error(err.stack);
}); I get this stacktrace:
|
This is a pretty good place to add it, given how |
Also, not sure how standard |
@jasonsaayman will you consider merging this? |
@jasonsaayman @andrew0 It looks like @ikonst's PR has been idle for a little bit since its last review. Is there any chance we might be able to get another round of review on it? 🙏 |
Currently, if you use axios with async / await, you get a stack trace like this:
It doesn't show you much about what called Axios., which makes debugging quite difficult!
This is because
settle
callscreateError
:https://github.com/axios/axios/blob/master/lib/core/settle.js#L12-L24
Which creates a new error with a brand new stack trace:
https://github.com/axios/axios/blob/master/lib/core/createError.js#L15-L18
Perhaps we can fix this by creating an error before the request goes out and stitching it to the new error's stack trace?
The text was updated successfully, but these errors were encountered: