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

Async validation failing causes Uncaught promise error #1297

Closed
kristian-puccio opened this issue Jul 7, 2016 · 54 comments
Closed

Async validation failing causes Uncaught promise error #1297

kristian-puccio opened this issue Jul 7, 2016 · 54 comments

Comments

@kristian-puccio
Copy link

The link in the docs to rc.3 is broken but you can see this in rc.2

Go to http://redux-form.com/6.0.0-rc.2/examples/asyncValidation/ and fail the validation.
You will get a undefined:1 Uncaught (in promise) Object {username: "That username is taken"} error

@Ruzo
Copy link

Ruzo commented Jul 11, 2016

Same error for me using axios.

@backnotprop
Copy link

backnotprop commented Jul 13, 2016

Also seeing this.

Would really like for the error to be passed down to the Form through props. There is an error property however it is undefined, the propsinvalid/valid both work respectively when validation fails. Also, it seems like a prop type of asyncErrors is supposed to exist, however not seeing it. Most likely a separate issue than the one above.

^^ solved the error prop issue (the payload wants a _error key/value):
throw { email: 'That email is registered already', _error: 'email-exists' };

@jmarceli
Copy link

jmarceli commented Aug 4, 2016

This problem is still visible in rc.4, any update on that? Maybe some workaround?

I've tried same example for 5.3.1 version (without any strange errors) http://redux-form.com/5.3.1/#/examples/asynchronous-blur-validation?_k=cbebna maybe it will give some clues how to fix this i v6.

@alyrik
Copy link

alyrik commented Aug 16, 2016

Still the same. It may even be reproduced with this demo
screenshot_2016-08-17_00-48-33

@NeXTs
Copy link
Contributor

NeXTs commented Aug 19, 2016

Due to inspecting devtools console seems to be that this issue wasn't fixed in rc.5 either :(

@Strato
Copy link
Contributor

Strato commented Sep 7, 2016

Having this issue with v6.0.2...

Seems to come from here:

var handleErrors = function handleErrors(rejected) {
    return function (errors) {
      if (errors && Object.keys(errors).length) {
        stop(errors);
        return Promise.reject(errors);
      } else if (rejected) {
        stop();
        throw new Error('Asynchronous validation promise was rejected without errors.');
      }
      stop();
      return Promise.resolve();
    };
  };

Once you got the errors and know the promise was rejected, why are you rejecting again? You're at the end of the promise chain so you should just swallow up the error.

I would remove this line:
return Promise.reject(errors);

@NeXTs
Copy link
Contributor

NeXTs commented Sep 7, 2016

@Strato could you make a PR please :)

@erikras
Copy link
Member

erikras commented Sep 15, 2016

Potential fix published in v6.0.3. Please confirm.

@NeXTs
Copy link
Contributor

NeXTs commented Sep 15, 2016

Unfortunately v6.0.3 doesn't help. Still get uncaught exception in console

@caiobalthazar
Copy link

Confirming that the issue still exists on v6.0.5.
I would like to add that it is easily reproducible using the async demo from the official website.
Simply type 'george' and see it happen. I hope that reproducing it makes it easier to fix.

@NeXTs
Copy link
Contributor

NeXTs commented Sep 23, 2016

Yayy! Finally! Waiting for new release )

@aliatsis
Copy link

Any ETA for when this will be published?

@erikras
Copy link
Member

erikras commented Oct 7, 2016

Published in v6.1.0.

@mschipperheyn
Copy link

The problem is back in 6.2.1: http://redux-form.com/6.2.1/examples/asyncValidation/

@Yagger
Copy link

Yagger commented Dec 8, 2016

Having same problem in v6.2.0

@Egidius
Copy link

Egidius commented Dec 9, 2016

same in 6.3.2

@JensenTStava
Copy link

Was anyone able to find a solution for this?

@Anarios
Copy link

Anarios commented Dec 20, 2016

Same problem in 6.3.2

@Anarios
Copy link

Anarios commented Dec 20, 2016

Solved it, make sure that you are returning the promise in your handleSubmit. I had it fetch(... whereas it should be return fetch(...

@markau
Copy link

markau commented Jan 17, 2017

Thanks @Anarios. For the benefit of anyone else, I did the throw new SubmissionError in my .then block (axios), and then my catch block became:

.catch(function (error) { throw error; }

@jampy
Copy link

jampy commented Feb 2, 2017

This is still unfixed in 6.5.0

@jampy
Copy link

jampy commented Feb 2, 2017

...and can be reproduced on http://redux-form.com/6.5.0/examples/asyncValidation/

Just enter something in the password field and then type "paul" in the user field. Then, while still having the user field focused (meaning that validation has not yet kicked in), klick on the submit button.

The validation error will show as expected, but there is also a unhandled Promise rejection in the console.

image

vsaarinen added a commit to lucified/minard-ui that referenced this issue Feb 5, 2017
This currently does not seem to work properly due to a bug in redux-form:
redux-form/redux-form#1297
redux-form/redux-form#1682

If/when this bug is fixed, we could consider moving to this format
@Blackclaws
Copy link

Blackclaws commented Feb 8, 2017

I've made an interesting find. I have the same problem and have a way to avoid it now.

function asyncValidateRegisterInput(values) {
  const { username, email, displayName } = values;
  const user = { username, email, displayName };
  return authClient.validateRegisterData(user).catch((err) => {
    const errors = {};
    err.messages.forEach((item) => {
      errors[item.type] = item.message;
    });
    throw errors;
  })
}

This produces the error Uncought in Promise even if the underlying Promise resolves (but returns a value).

If I change this to:

function asyncValidateRegisterInput(values) {
  const { username, email, displayName } = values;
  const user = { username, email, displayName };
  return authClient.validateRegisterData(user).catch((err) => {
    const errors = {};
    err.messages.forEach((item) => {
      errors[item.type] = item.message;
    });
    throw errors;
  }).then(() => Promise.resolve());
}

This gets rid of the error.

Apparently returning ANYTHING from the resolved promise results in it being treated as an error. Instead of just treating rejection as an error.

I've tested this by changing Promise.resolve() to Promise.resolve("test") and was able to get the error again.

@Merri
Copy link

Merri commented Feb 16, 2017

This is how async validation works in practise right now:

  1. If you have errors just return an object with the fields.
  2. If no errors then return null (null is nice when "nothing" is an intended result)

Example:

function asyncValidate(values) {
    // Assume errors is already in Redux Form compatible format.
    // Here catch essentially just ignores error if:
    // 1) destructuring errors failed in .then
    // 2) fetchStuff threw an error, for example if you have custom logic in case fetch() response.ok is false
    return fetchStuff(values).then(
        ({ errors }) => errors || null
    ).catch(() => null)
}

Essentially: the docs are incorrect. You never need to throw.

The major "flaw" in the current design is that rejecting is not really handled properly, which is the bug you see. And in general when managing errors in promises you should always throw new Error(reason) as at least I've come to expect to have an Error instance when doing .catch(). It gets mentally confusing to manage errors if you can't know what to expect!

I think the Uncaught "bug" doesn't need to be fixed as people can simply change their code to not to throw, instead the docs need to be fixed so that they match the actual usage as the current example is confusing.

To correct the issue with promise usage there are a couple of hard questions:

  1. Should validation only fail if the promise is rejected? (To match usage of stuff like SubmissionError.)
  2. Should there be a custom error object like AsyncValidationError?
  3. Should validation be able to distinguish between warning level and error level errors? (there seems to exist input.warning in props but I have never used it yet; have not yet researched what the warning thing is for in redux-form's case)

Related to this I happen to have a case where I can get error and/or warning level validation errors: warning level can be ignored but error level cannot. The current asyncValidate doesn't really support this use case so I have to "manually hack" with component state.

It would be nice if the async validation and it's usage of promises and errors is rethought, and then changed if seen worthwhile.

@irisSchaffer
Copy link

irisSchaffer commented Apr 4, 2017

In case anyone else has the same silly mistake. As outlined in #2269 (comment), if using redux-form/immutable, make sure to also import SubmissionError from there:

import { SubmissionError } from 'redux-form/immutable'

Now it works even with async functions:

export const submit = (id) => async (data) => {
  try {
     await sendForm(id, data)
  } catch (e) {
    if (e.code && e.code === 'memberExists') {
      throw new SubmissionError({ _error : 'You have already signed up!' })
    } else {
      throw new SubmissionError({ _error : 'An unexpected error occurred. Please try again later.' })
    }
  }
}

@ianlyons
Copy link

@irisSchaffer i ran into this, too... for subsequent readers, it's worth calling out that ReduxForm doesn't really play well with submitting anything outside of the context of its own components, so i'm ending up (like you) using a higher order function to pass initial values in and then let the form call the returned function and retain access to those values through the closure.

kinda funky... i want to dig into this and figure out if there's a more robust or stabler way to use these guys.

@ghost
Copy link

ghost commented Apr 21, 2017

I was getting this error even on submit validation (like @waynebrantley) and was racking my brains for couple of days. I found that SubmissionError I was throwing even was not instanceof SubmissionError...

It seems that the reason was how I imported SubmissionError:

import SubmissionError from 'redux-form/lib/SubmissionError';

When I changed it to:

import { SubmissionError } from 'redux-form';

it started to work as described in documentation.

@pacozaa
Copy link

pacozaa commented Jun 26, 2017

I have no problem throwing error but how to return error message back to UI?

I use the same function as my submitValidate which works fine and throw the error to UI but with asyncValidate it only throw error in console log but not in UI

@pacozaa
Copy link

pacozaa commented Jun 26, 2017

I use this in meteor
@irisSchaffer
I don't have to use

import { SubmissionError } from 'redux-form/immutable'

just

import { SubmissionError } from 'redux-form'

is fine.

Here is my solution

export const asyncValidate = values => {
 
  return new Promise((resolve, reject) => {
      reject({ yourFieldName: 'your error message' })
    })
}

credit: the idea from this issue #2021
Best,

@sebmor
Copy link

sebmor commented Jul 13, 2017

This definitely needs better documentation

@gustavohenke
Copy link
Collaborator

@sebmor PRs are welcome

@isehrob
Copy link

isehrob commented Jul 13, 2017

The problem is present in v7.0 again. Upgrading to this version produced the error. And after many hours of unsuccessfull attempts, tried to downgrading redux-form to v6.5, and async validation started to work as intended.

@Roman-Maksimov
Copy link
Contributor

Roman-Maksimov commented Jul 21, 2017

As a solution you can use such kind of hack:

render() {
  const { handleSubmit } = props;

  const onSubmit = e => {
    e.preventDefault();
    handleSubmit().catch(() => null);
  };

  return (
    <form onSubmit={onSubmit}>
       ...

Also I've created a Pull Request to fix the bug #3227
Will waiting for the review from authors.

@danielrob
Copy link
Collaborator

Re-opening as this issue appears still active.

@danielrob danielrob reopened this Jul 25, 2017
@danielrob
Copy link
Collaborator

This expected to be fixed in 7.0.3 🎉. Is someone who was affected by this willing to confirm?

@isehrob
Copy link

isehrob commented Jul 27, 2017

Yep! Updated redux-form to v7.0.3 and it is working without any problem!

@Roman-Maksimov
Copy link
Contributor

Also can confirm. The error doesn't appear in 7.0.3

@danielrob
Copy link
Collaborator

Thanks everyone!

@antoinerousseau
Copy link

If you still have the error, make sure you actually return a Promise in your submit function:

const workingSubmit = (values) => {
  return Promise.reject(new SubmissionError({_error: 'test'}))
}

const nonWorkingSubmit = (values) => {
  Promise.reject(new SubmissionError({_error: 'test'}))
}

The latter will show an uncaught Promise.

@geminiyellow
Copy link

i try to trigger asyncValidate in the form's onChange, it still have the error. 7.0.3

@emanuellarini
Copy link

emanuellarini commented Aug 22, 2017

I still got the error in 7.0.3 and I did like described in docs for an exchange of a warn (removed the SubmissionError):

Broken way:
throw new SubmissionError({ email: 'That email is taken' })

Works but gave me warn of "Expected an object to be thrown":
throw { email: 'That email is taken' }

This code is inside an Axios request which validates if the email is registered.

@b0gok
Copy link
Contributor

b0gok commented Jan 19, 2018

Here is an example of asyncValidation in redux-form 7.2.1:
https://codesandbox.io/s/8on6qk15j

@erikras can you check it, please?

@prakashsvmx
Copy link

+1

@aliaksandr-kazarez
Copy link

I'm having the same issue when trying to submit via ActionCreator. So instead of clicking submit button, I'm dispatching submit action, which cause exactly the same error.

https://codesandbox.io/s/mq94q867p8

@vah7id
Copy link

vah7id commented Mar 15, 2019

+1

I'm having the same issue when trying to submit via ActionCreator. So instead of clicking submit button, I'm dispatching submit action, which cause exactly the same error.

https://codesandbox.io/s/mq94q867p8

@Sriram-Kilambi
Copy link

Sriram-Kilambi commented Mar 22, 2019

I came across the same issue in V 8.1.0. I solved it by writing the AXIOS api call using Async/Await.
This is the example for the asyncValidate.js File -

import axios from 'axios';

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

const asyncValidate = (values /* , dispatch */) => sleep(1000).then(async () => { // simulate server latency
await axios.get('https://jsonplaceholder.typicode.com/users').then((res) => {
console.log('Response from JSONPlaceholder', res);
console.log('THE VALUES OBJECT CONTAINS EMAIL as', values.email);
if (values.email === res.data[0].email) {
// eslint-disable-next-line no-throw-literal
throw { email: '' };
} else {
// eslint-disable-next-line no-throw-literal
throw { email: 'Email does not exist' };
}
});
});

export default asyncValidate;

@DFallas
Copy link

DFallas commented Feb 12, 2020

I'm having the same issue, in version: 7.4.2, has someone some of the previous suggested fixes won't work for me 1 or 2, 3, 4
Does anyone has any news on this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests