1

I making a multi-upload file form.

Upon user cancellation, once the corresponding axios call get cancelled using cancel(), I having a weird behaviour. My axios call get caught inside the then() whereas it should be caught inside of catch(). The response inside of then() returns undefined.

I am having a hard time figuring if I did something wrong on the front-end part, I think my call is may be missing some headers or maybe it's on the backend part ?

      const payload = { file, objectId: articleId, contentType: 'article' };

      const source = axios.CancelToken.source();

      // callback to execute at progression
      const onUploadProgress = (event) => {
        const percentage = Math.round((100 * event.loaded) / event.total);
        this.handleFileUploadProgression(file, {
          percentage,
          status: 'pending',
          cancelSource: source,
        });
      };

      attachmentService
        .create(payload, { onUploadProgress, cancelToken: source.token })
        .then((response) => {
          // cancelation response ends up here with a `undefined` response content
        })
        .catch((error) => {
          console.log(error);
          // canceled request do not reads as errors down here
          if (axios.isCancel(error)) {
            console.log('axios request cancelled', error);
          }
        });

the service itself is defined below

export const attachmentService = {
  create(payload, requestOptions) {
    // FormData cannot be decamelized inside an interceptor so it's done before, here.
    const formData = new FormData();
    Object.entries(payload).forEach(([key, value]) =>
      formData.append(decamelize(key), value),
    );
    return api
      .post(resource, formData, {
        headers: {
          'Content-Type': 'multipart/form-data',
        },
        ...requestOptions,
      })
      .then((response) => {
        console.log(response, 'cancelled request answered here as `undefined`');
        return response.data;
      })
      .catch((error) => {
        // not caught here (earlier)
        return error.data;
      });
  },
};

cancellation is called upon a file object doing

file.cancelSource.cancel('Request was cancelled by the user');
petitkriket
  • 154
  • 4
  • 19
  • Why would it throw an error? It's a cancellation, not an error. I don't see why it should be caught as an error. – Jeremy Thille Apr 27 '21 at 12:51
  • 1
    Please could you post your code that should cancel this request (the actual method call against the `source` variable as per https://github.com/axios/axios#cancellation) – Matthew Spence Apr 27 '21 at 12:51
  • @JeremyThille it's meant to be an error and it's caught inside of catch() in axios docs. – petitkriket Apr 27 '21 at 13:17
  • @MatthewSpence added the call below ! – petitkriket Apr 27 '21 at 13:18
  • This means that it was caught previously. This is what your code shows, `.catch((error) => { return error.data; })`. If you don't want it to be caught, don't catch it. Also, catching errors early doesn't make sense because you won't be able to distinguish them from successful results later. – Estus Flask Apr 27 '21 at 14:31
  • @EstusFlask it was not caught earlier in the service, it wen to the `then()` as it's returned later – petitkriket Apr 27 '21 at 15:33
  • 1
    You either have a problem with correctly debugging *cancelled request answered here* and *not caught here* places, or it was caught somewhere before, including interceptors. You didn't show what `api` is. Any way, the cancellation in Axios results in a rejection and triggers `catch`. If this differs for you then the problem is specific to your case, this means that you caught cancellation error, deliberately or not. Please, provide https://stackoverflow.com/help/mcve that can reproduce the problem. – Estus Flask Apr 27 '21 at 15:41

1 Answers1

1

As suggested by @estus-flask in a comment, the issue is that I was catching the error inside of the service (too early). Thank you!

export const articleService = {
  create(payload, requestOptions) {
    // FormData cannot be decamelized inside an interceptor so it's done before, here.
    const formData = new FormData();
    Object.entries(payload).forEach(([key, value]) =>
      formData.append(decamelize(key), value),
    );
    return api.post(resource, formData, {
      headers: {
        'Content-Type': 'multipart/form-data',
      },
      ...requestOptions,
    });
  },
};
petitkriket
  • 154
  • 4
  • 19