Skip to content

Include more information in error message when fetch() fails #647

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

Merged
merged 1 commit into from
May 20, 2017

Conversation

albrow
Copy link
Contributor

@albrow albrow commented May 20, 2017

I recently ran into a frustrating issue when running browser tests for go-humble/rest. The only error message I was seeing was:

net/http: fetch() failed

After I made a small tweak to GopherJS, the error message turns into:

net/http: fetch() failed: TypeError: Failed to execute 'fetch' on 'Window': Request with GET/HEAD method cannot have body

With this additional information I was able to quickly fix the bug in go-humble/rest and move on.

I can understand if you prefer to keep the error message short, but it would have saved me a lot of time to have this longer error message available from the beginning. I suspect this will save other people some time too.

@dmitshur
Copy link
Member

No, there wasn't an intention to keep the message short, so this is a welcome improvement, thanks.

@@ -116,7 +117,7 @@ func (t *fetchTransport) RoundTrip(req *Request) (*Response, error) {
},
func(reason *js.Object) {
select {
case errCh <- errors.New("net/http: fetch() failed"):
case errCh <- fmt.Errorf("net/http: fetch() failed: %s", reason.String()):
Copy link
Member

@dmitshur dmitshur May 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you be sure that reason will never be nil? Otherwise it'd be a nil pointer dereference panic, right?

Copy link
Member

@dmitshur dmitshur May 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it might never be nil for the same reason result is never nil in the success case.

I looked at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then, and don't see an explicit confirmation that reason won't be nil...

Is there a way we can be sure?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I'm not 100% sure and it's pretty easy to add this check.

Copy link
Member

@dmitshur dmitshur May 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be nice if we could find out. That way, the code could be simpler.

Copy link
Member

@dmitshur dmitshur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we can't find a conclusive answer about whether reason can have null value, then this will have to do. But if we can, that'd be better. I'll give it some time, maybe someone can help.

I left some minor style comments meanwhile.

@@ -115,8 +116,15 @@ func (t *fetchTransport) RoundTrip(req *Request) (*Response, error) {
}
},
func(reason *js.Object) {
var jsErr error
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style-wise, just name this err. I don't see why it should be jsErr.

if reason != nil {
jsErr = fmt.Errorf("net/http: fetch failed: %s", reason.String())
} else {
jsErr = errors.New("net/http: fetch() failed")
Copy link
Member

@dmitshur dmitshur May 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does one message have "fetch" but the other "fetch()"? It'd be better to make them consistent.

@dmitshur
Copy link
Member

I found that it's indeed possible to pass null as a rejection reason with JavaScript promises:

var p1 = new Promise( (resolve, reject) => {
  //resolve('Success!');
  // or
  reject (null);
} );

p1.then( value => {
  console.log(value); // Success!
}, reason => {
  console.log(reason === null); // true
  console.log(reason);          // "null"
} );

(On JSFiddle.)

That prints true and null.

So the question becomes, does any implementation of Fetch API ever pass null as a rejection reason (i.e., is it allowed by its specification).

@albrow
Copy link
Contributor Author

albrow commented May 20, 2017

I addressed the style comments.

As far as I can tell, neither the ECMAScript 2015 Spec for Promises nor the Living Standard for the Fetch API explicitly forbid a null value showing up here.

A quick test shows that Chrome allows you to do things like this:

Promise.reject(null).catch(function(e) {console.log(e)})
Promise.reject(undefined).catch(function(e) {console.log(e)})

I'm not sure what the best course of action is, so I'll defer to you or anyone else who can chime in.

@dmitshur
Copy link
Member

dmitshur commented May 20, 2017

Ah, well, I just remembered one GopherJS-specific thing. It's actually safe to call the *js.Object type conversion methods on a nil value of *js.Object. It's a way of converting null to that type.

E.g., this is fine:

https://gopherjs.github.io/playground/#/kY9ne7yWeM

It's effectively equivalent to:

func (o *Object) String() string {
    if o == nil {
        return "null"
    }
    return string(*o) // not really, but you get the idea
}

So, no panic is possible. You can revert to your original code, since it's shorter and better.

That said, we might want to improve the documentation of js package to mention this. It's also related to #617 (/cc @myitcv).

@albrow albrow force-pushed the verbose-fetch-errors branch from 6a451b8 to c7fd67f Compare May 20, 2017 22:33
@albrow
Copy link
Contributor Author

albrow commented May 20, 2017

Cool. I reverted back to the original state of this PR (without the nil check).

Copy link
Member

@dmitshur dmitshur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks!

@dmitshur dmitshur merged commit 6997325 into gopherjs:master May 20, 2017
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

Successfully merging this pull request may close these issues.

2 participants