Skip to content
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

Axios catch error returns javascript error not server response #960

Closed
jiimmeh opened this issue Jun 17, 2017 · 87 comments
Closed

Axios catch error returns javascript error not server response #960

jiimmeh opened this issue Jun 17, 2017 · 87 comments

Comments

@jiimmeh
Copy link

jiimmeh commented Jun 17, 2017

Im trying to catch validation errors from the server.

Code:

axios.post('/formulas/create', {
       name: "",
       parts: ""
})
.then( 
	(response) => { console.log(response) },
	(error) => { console.log(error) }
);

Console log output

Error: Request failed with status code 422
    at createError (app.js:6765)
    at settle (app.js:29489)
    at XMLHttpRequest.handleLoad (app.js:6600)

Network tab output
{"name":["The name field is required."],"parts":["The parts field is required."]}

I should be seeing an object that contains JSON form validation as that is the response in my network tab, i seem to get the JS catch output?

Also tried the following:

axios.post('/formulas/create', {
	name: "",
	parts: ""
})
.then(response => { 
	console.log(response)
})
.catch(error => {
    console.log(error)
});

Same result

More people seem to have the same problem using the same enviroment as me here.
https://laracasts.com/discuss/channels/vue/issues-with-axios-catch-method

  • Axios version: ^0.16.2
  • VueJS 2.3.4
  • Vue-template-compiler 2.3.4
  • Laravel-mix
  • Environment: node v6.4.0, chrome 58, Mac OSX 10.12.4
@alsofronie
Copy link

I have exactly the same environment. Try this:

axios.post('/formulas/create', {
	name: "",
	parts: ""
})
.then(response => { 
	console.log(response)
})
.catch(error => {
    console.log(error.response)
});

Modify from console.log(error) to console.log(error.response) in catch.

You can also use a global interceptor and reject only the error.response. The problem is when the console.log tries to output the error, the string representation is printed, not the object structure, so you do not see the .response property.

@vsg24
Copy link

vsg24 commented Aug 7, 2017

In case anybody is wondering how to reject only the response property, here's how to do it:

axios.interceptors.response.use((response) => {
    return response;
}, function (error) {
    // Do something with response error
    if (error.response.status === 401) {
        console.log('unauthorized, logging out ...');
        auth.logout();
        router.replace('/auth/login');
    }
    return Promise.reject(error.response);
});

The important part is return Promise.reject(error.response);

@gopal-g
Copy link

gopal-g commented Sep 27, 2017

This yields the same result incase if the above solution messes up your JS file syntax while indenting or minifying :)

axios
.post('ajax/register/otp', this.registerData)
.then(function (response) {
       return otpSent(response)
})
.catch(function (error) {
      console.log(error.response);
 });

@pedro-mass
Copy link

@gopal-g that's undefined for me.

@gopal-g
Copy link

gopal-g commented Oct 18, 2017

Well @pedro-mass in that case there might be no response from server side. in my scenario my response was JSON when error occured I could get the response using error.response

@pedro-mass
Copy link

@gopal-g If I'm watching the Network tab in dev tools, I can see the response. It's a 401 if that makes a difference.

@mu-yu
Copy link

mu-yu commented Oct 31, 2017

I have the same error with @pedro-mass 's.

here is my code

async function test () {
try {
  let res = await axios.get('/xxxxx/xxxx')

} catch (e) {
  console.log(e.response) // undefined
}
}

@fabiorecife
Copy link

using "error.response" does not work, for me. The problem occurs when I disconnected the database server and my web server returned error 500.

Network tab in dev tools

response code: 500
response body:

{
  "error": {
    "statusCode": 500,
    "name": "Error",
    "message": "read ETIMEDOUT",
    "code": "ETIMEDOUT",
    "errno": "ETIMEDOUT",
    "syscall": "read",
    "stack": "Error: read ETIMEDOUT\n    at exports._errnoException (util.js:1050:11)\n    at TCP.onread (net.js:582:26)"
  }
}

chrome console error:

Uncaught (in promise) Error: Request failed with status code 500
    at createError (createError.js:15)
    at settle (settle.js:18)
    at XMLHttpRequest.handleLoad (xhr.js:77)

version

"axios": "^0.15.3"

@alsofronie
Copy link

There is a catch in catch: if the error occurs before the request is made, then in catch you will not have the err.response property, because... well... there is no response. So, the catch will catch any error. The same applies in the situations like the one from @fabiorecife when there is no response because of a network failure. Do not treat the err as a HTTP error because this is not always the case.

@robbiemu
Copy link

robbiemu commented Nov 17, 2017

@alsofronie so what is the preferred method of handling (distinguishing one from another) for example preflight failures like 413?

@paolavness
Copy link

I'm getting a similar issue - Chrome devtools is showing a 401, the response is {"message":"Identity token has expired"} and I am catch( (error) => {...}) - but error.response blank. I am wondering if this is because the preceding OPTIONS call associated with the GET has a status of 200. What to do in this case and where is the right place to retrieve the 401 status code?

@mrchief
Copy link

mrchief commented Nov 29, 2017

@robbiemu I think its already documented: https://github.com/axios/axios#handling-errors

@paolavness
Copy link

@mrchief thanks for this, good to go over it again. In my case, this solution has works in most cases but the current problem I am experiencing is that the error.response object is present, but fields are undefined, any calls to values inside the response object result in an error.

@mrchief
Copy link

mrchief commented Nov 29, 2017

@paolavness I'd suggest to open up a new issue instead of commenting here. Not many watch closed issues. Or maybe even ask it on StackOverflow.

@paolavness
Copy link

@mrchief Ah this is closed, thanks for pointing that out. will do.

@dbshoupe
Copy link

I had the same issue. Ultimately, I changed the error code from 401 to 403 and everything worked as I expected it to. I'm guessing the reason for the empty error object and resulting javascript error has to do with this statement that I found in the documentation for 401 errors:

"[A 401 error] response must include a WWW-Authenticate header field containing a challenge applicable to the requested resource."

So if you are going to utilize a 401 error, you must include a www-authenticate header field. If you don't want to do this, just use a 403 error.

@juliano-barros
Copy link

Good morning guys, I had this issue, however, I fixed it changing my apache configuration to enable cors on my server. Have a look at link below

https://enable-cors.org/server_apache.html

@richellyitalo
Copy link

You can debug all response only with console.log(JSON.stringify(error))

@maythukha
Copy link

axios.post(url)
.then((response) => {
// something
})
.catch((response) => {
if (response.status == undefined) {
alert('unauthorized')
}
})

@petruscurtu
Copy link

I had exactly the same problem described by @fabiorecife . I solved it but it is not the most elegant solution and I do not understand why this is needed.

.catch(error=>{
let errorObject=JSON.parse(JSON.stringify(error));
console.log(errorObject);
dispatch(authError(errorObject.response.data.error));
})

This produces the expected results in the errorObject variable.

@luxueyan
Copy link

luxueyan commented May 26, 2018

@petruscurtu I have the same problem! It dose not work for me!
image
I don't khnow why it throw 'no Access-control-allow-origin', but the server has set it! The response header is ok
image

Resolved. The auth api was not responsing the right header that must have the Access-control-allow-origin

@petruscurtu
Copy link

petruscurtu commented May 26, 2018

@luxueyan I do not know what the problem could be since I do not know how you handle CORS on your server. As far as axios is concerned, I can see a config and request object in your console output. I think that you should check that output. It might be related to the format of the response your server is sending back.

@chiefie
Copy link

chiefie commented May 28, 2018

@luxueyan It seems that you had your Access-control-allow-origin set up for http://localhost:8081 (assuming this is set on the server with this address http://10.31.143.32:8080?) Can you check what is the URL you're running this project from? Is it http://localhost:8081? If it is not, even if the port number is different, then it is violating the CORS domain rules.

@luxueyan
Copy link

@petruscurtu The output is 'JSON.parse(JSON.stringify(error))' in interceptor of response. There has not response property

@amdp
Copy link

amdp commented Jul 8, 2019

In my experience:

"Modify from console.log(error) to console.log(error.response) in catch."

worked better with console.log(error.response.data) in catch.

@abisael
Copy link

abisael commented Jul 14, 2019

axios.interceptors.response.use(null, error => {
return error.response;
});

getClients: async (state) => {
const res = await axios.get(${BASE_API}/clients);
console.log('res',res);
if (res){
state.commit("setClient", res.data);
}
}

@konstantinblaesi
Copy link

Another option

/**
 * Whenever error.message is accessed we want to se the full API error message (JSON) if it's present
 * not just some generic http status code + message
 * see https://github.com/axios/axios/issues/960 for context
 *
 * @param axios
 */
export function extractAPIErrorResponse(axios: AxiosInstance) {
    axios.interceptors.response.use(undefined, function (error: AxiosError) {
        (error as any).originalMessage = error.message;
        Object.defineProperty(error, "message", { get: function () {
            if (!error.response) {
                return (error as any).originalMessage;
            }
            return JSON.stringify(error.response.data);
        }});
        return Promise.reject(error);
    })
}

@drsoft28
Copy link

drsoft28 commented Oct 13, 2019

Try{
Await this.$axios .....
}catch(e)
{
console.log(e)

}

@shoki61
Copy link

shoki61 commented Oct 14, 2019

axios.get("https://......") 
     .then( response => {
          return response
}).catch( () => {
         store.dispatch("errorComponentMethod")   // if there's an error, method is dispatched
})
//////////////////////////////////////
actions : {
      errorComponentMethod(){
              router.push("/errorComponent")     // method routes to error component
      }
}

@lucasluca
Copy link

Great thanks ! Helped a lot!

@valarisolutionsTeam
Copy link

valarisolutionsTeam commented Nov 16, 2019

still getting this problem. on chrome debugger the response is correct but axios returns a general "Request failed with status code 403" instead

@HoogsterInc
Copy link

HoogsterInc commented Nov 16, 2019

I'm still having this and I am really confused. I tried to catch it is the comments above - but why exactly does axios return undefined when there is an error?
try{ const res = await axios.get("someurl"); return res; } catch(e) { console.log(e); }
res is undefined even though the server is sending back a response with a message in it for WHY it didn't work. And I can't get to that data... why??

**EDIT: found my bug - nothing wrong for me with axios. See my comment two comments down. In short my interceptors were not passing the error data back through the axios pipeline so I was always getting undefined.

@konstantinblaesi
Copy link

@HoogsterInc Have look at the TypeScript definitions here
you could do something like this

try {
   axios.get(...)
} catch (error) {
   if (error.reponse) {
      // http status 4x, 5xx
   } else {
      // network error like timeout, connection refused etc...
   }
}

@HoogsterInc
Copy link

Thank you for the response trying to help @konstantinblaesi -- I figured out my issue.

For me I had an interceptor set up to check the user's authentication, which if they become unauthed with send a specific error code. I was not however passing along the error data when the error did not match an unauthed code... sigh... silly bad mistake. So after checking for the unauthenticated error code I made sure to return Promise.reject(error); - That solved my problem and the error data comes in full now.

@RodrigoPauletti
Copy link

You can use err.toJSON()

catch((err) => {
    console.log(err.toJSON()); // Return error object
});

https://github.com/axios/axios#handling-errors

@vidorifaldy
Copy link

vidorifaldy commented Jan 27, 2020

(set for global)

in the main.js

import axios from 'axios'

var instance = axios.create(
 { validateStatus: function (status) {
    return status < 600; #you can change this with another value
  }
 }); 

or
(set for particular)

  axios.post('/formulas/create', {
       name: "",
       parts: ""
  }, { validateStatus: function (status) {
          return status < 600; // Reject only if the status code is greater than or equal to 500
        }})
    .then( 
   (response) => { console.log(response) },
   (error) => { console.log(error) }
   );

@xgqfrms
Copy link

xgqfrms commented Feb 6, 2020

Axios & catch 500 error response data

const log = console.log;

  updateData(options = {}, flag = false){
    let url = `/opapi/appDownloadGuide/update`;
    let message = '更新成功!';
    let errorMessage = '更新失败!';
    if (flag) {
      message = '添加成功!';
      errorMessage = '添加失败!';
      url = `/opapi/appDownloadGuide/add`;
    }
    axios
    .post(url, options)
    .then(res => {
      // ❓🤔️500 , 在这里拦不住呀?
      log(`res`, res, res.status);
      return res.data;
    })
    .then(json => {
      const {
        code,
        success,
        data,
        errorCode,
        errorHint,
      } = json;
      if(code === 200) {
        this.$message({
          type: 'success',
          message,
        });
        this.init();
      } else{
        this.$message({
          type: 'error',
          message: `${errorMessage}: ${errorHint ? errorHint : ""}`,
        });
      }
    })
    .catch(err => {
      // 👌在这里拦截 error data!
      log(`error.response`, err.response);
      const {
        data,
        status,
        statusText,
      } = err.response;
      this.$message({
        type: "error",
        message: `${statusText}-${status}: ${data || ""}`,
        // message: "不能重复创建",
      });
      console.error(`500 err`, err);
    });
  },

https://stackoverflow.com/questions/38798451/how-to-catch-and-handle-error-response-422-with-redux-axios

@sunithakk
Copy link

I have exactly the same environment. Try this:

axios.post('/formulas/create', {
	name: "",
	parts: ""
})
.then(response => { 
	console.log(response)
})
.catch(error => {
    console.log(error.response)
});

Modify from console.log(error) to console.log(error.response) in catch.

You can also use a global interceptor and reject only the error.response. The problem is when the console.log tries to output the error, the string representation is printed, not the object structure, so you do not see the .response property.

Not working for me

@sunithakk
Copy link

@gopal-g that's undefined for me.

@gopal-g yes same undefined im getting.

@garyo
Copy link

garyo commented Mar 19, 2020

I'm using Axios 0.19.2. I added @konstantinblaesi 's solution:

Another option

/**
 * Whenever error.message is accessed we want to se the full API error message (JSON) if it's present
 * not just some generic http status code + message
 * see https://github.com/axios/axios/issues/960 for context
 *
 * @param axios
 */
export function extractAPIErrorResponse(axios: AxiosInstance) {
    axios.interceptors.response.use(undefined, function (error: AxiosError) {
        (error as any).originalMessage = error.message;
        Object.defineProperty(error, "message", { get: function () {
            if (!error.response) {
                return (error as any).originalMessage;
            }
            return JSON.stringify(error.response.data);
        }});
        return Promise.reject(error);
    })
}

This worked for me, thanks so much @konstantinblaesi ! I don't understand why Axios's default behavior isn't like this -- the standard behavior is to drop the "message" part of the original error, which I would think is the most important part!

Just to be clear, in my app, my server is returning a 400 error (which should be a response):

% curl -X POST http://my-server/api -d '{"foo": "bar"}'
{"status": 400, "message": "missing param XYZ"}

and without this fix, I get from Axios an error object that contains only name, stack, config (which has the original request), and no "response". But with this fix the error contains the correct message property from the server.

As for why there is no "response" property without this fix, it seems to be related to settle in axios.js around line 1171:

        module.exports = function settle(resolve, reject, response) {
          var validateStatus = response.config.validateStatus;
          if (!validateStatus || validateStatus(response.status)) {
            resolve(response);
          } else {
            reject(createError(
              'Request failed with status code ' + response.status,
              response.config,
              null,
              response.request,
              response
            ));
          }
        };

and you can see it doesn't pass through response.message when creating the error. In addition, in my app I don't see the response in error.response, there's no such property -- I don't understand that. But anyway the above fix works for me.

@4fdal
Copy link

4fdal commented Apr 4, 2020

Im trying to catch validation errors from the server.

Code:

axios.post('/formulas/create', {
       name: "",
       parts: ""
})
.then( 
	(response) => { console.log(response) },
	(error) => { console.log(error) }
);

Console log output

Error: Request failed with status code 422
    at createError (app.js:6765)
    at settle (app.js:29489)
    at XMLHttpRequest.handleLoad (app.js:6600)

Network tab output
{"name":["The name field is required."],"parts":["The parts field is required."]}

I should be seeing an object that contains JSON form validation as that is the response in my network tab, i seem to get the JS catch output?

Also tried the following:

axios.post('/formulas/create', {
	name: "",
	parts: ""
})
.then(response => { 
	console.log(response)
})
.catch(error => {
    console.log(error)
});

Same result

More people seem to have the same problem using the same enviroment as me here.
https://laracasts.com/discuss/channels/vue/issues-with-axios-catch-method

  • Axios version: ^0.16.2
  • VueJS 2.3.4
  • Vue-template-compiler 2.3.4
  • Laravel-mix
  • Environment: node v6.4.0, chrome 58, Mac OSX 10.12.4

axios.post('/formulas/create', {
name: "",
parts: ""
})
.then(
(response) => { console.log(response) },
).catch(err => consol.log(err.response.data)});

@chandukasm
Copy link

error.response is an object , it will output [object,object] in console log.
you have to use error.reposne.data to access the error message.
refer : https://itnext.io/javascript-error-handling-from-express-js-to-react-810deb5e5e28

@garyo
Copy link

garyo commented Apr 6, 2020

@chandukasm yes but in my case I do not have an error.response -- it is undefined, even though the request was sent and the response received by express. Also see my comment above; the message is ignored (replaced by a generic message) even when a response exists.

@gopal-g
Copy link

gopal-g commented Apr 13, 2020

error.response is an object , it will output [object,object] in console log.
you have to use error.reposne.data to access the error message.
refer : https://itnext.io/javascript-error-handling-from-express-js-to-react-810deb5e5e28

if you see [object,object] on console.log then just do JSON.stringify(error.response) to see the actual error.

@brokenthorn
Copy link

There is no error.response object.

return this.$axios
  .post(postUrl, payload, { responseType: 'json' })
  .then(
    (response) => {
      this.message = `RESP: ${JSON.stringify(response)}`;
    },
    (reason) => {
      this.message = `REAS: ${JSON.stringify(reason)}`;
    }
  )
  .catch((err) => {
    this.message = `CATCH: ${JSON.stringify(err)}`;
  });

payload contains a bad value on purpose to trigger HTTP 422, which in Postman works as expected and the server (LB4) gives back complete error in JSON format explaining where the input data was wrong, but in axios, the error.response object is undefined.

@axios axios locked and limited conversation to collaborators May 22, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests