Skip to content

util: add util/errors - #38575

Closed
jasnell wants to merge 1 commit into
nodejs:masterfrom
jasnell:add-util-errors
Closed

jasnell wants to merge 1 commit into
nodejs:masterfrom
jasnell:add-util-errors

Conversation

@jasnell

@jasnell jasnell commented May 6, 2021 •

Copy link
Copy Markdown
Member

Exports a subset of internal/errors as require('util/errors').

The reason for util/errors is because there is already a errors
module on npm that has a non-trivial number of downloads per week.
Unfortunately that makes it semver-major

Signed-off-by: James M Snell [email protected]
Fixes: #38361
Fixes: #14554

@jasnell jasnell added the semver-major PRs that contain breaking changes and should be released in the next major version. label May 6, 2021
@github-actions github-actions Bot added build Issues and PRs related to Node.js builds or CI infrastructure. needs-ci PRs that need a full CI run. labels May 6, 2021
@mcollina

mcollina commented May 6, 2021

Copy link
Copy Markdown
Member

I'm +1

@mcollina

mcollina commented May 6, 2021

Copy link
Copy Markdown
Member

I think we should also expose the mechanism to create errors-with-codes. I did https://github.com/fastify/fastify-error to map the behavior of core.

@jasnell

jasnell commented May 7, 2021 •

Copy link
Copy Markdown
Member Author

@mcollina

I'm +1

Which are you +1 about? That we should export all of the ERR_ constructors?

It's important to keep in mind that this is not 100% of the error codes we use. There are several raised from C++ that are not covered by the internal/errors exports.

@mcollina

mcollina commented May 7, 2021

Copy link
Copy Markdown
Member

I'm +1 to exporting the JS ones, e.g. internal/errors.

@jasnell
jasnell marked this pull request as ready for review May 7, 2021 16:13
@jasnell

jasnell commented May 7, 2021

Copy link
Copy Markdown
Member Author

@mcollina @ronag ....

Ok, I've added a utility method to this that allows creating custom error types with codes...

const {
  makeErrorWithCode,
} = require('util/errors');

const messages = new Map([
  ['FOO', 'hello %s'],
  ['BAR', (name) => `hello ${name}`],
]);

const FOO = makeErrorWithCode('FOO', { Base: TypeError, messages });

throw new FOO('world');  // message: hello world

I've added basic documentation. What I'm not sure about is how we should document the constructors for the various ERR_ errors.

@jasnell
jasnell force-pushed the add-util-errors branch from c70a8e2 to 457afdd Compare May 7, 2021 22:34
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@joyeecheung

Copy link
Copy Markdown
Member

Should we export all of the ERR_* constructors like this?

What's the upside of exporting the constructors? The constructors take custom arguments and without documentations of the signatures they would be rather difficult to use, even though the sigantures can be quite unstable, since we change the message formatters all the time, adding more details. Doing a instanceof check with the constructors also seems less reliable than just checking the error.code property, which was what these errors were designed for.

@mcollina mcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Good work!

Comment thread doc/api/errors.md Outdated
@targos

targos commented May 10, 2021

Copy link
Copy Markdown
Member

Should we export all of the ERR_* constructors like this?

I could change my mind but I'm currently -1 on this, unless there's a very good reason to do it.
If such a reason exists, I think we should at least make sure that changing ERR_* constructors is never semver-major.

@jasnell
jasnell force-pushed the add-util-errors branch 2 times, most recently from 1b97759 to 0ce6341 Compare May 10, 2021 22:23
@jasnell

jasnell commented May 10, 2021

Copy link
Copy Markdown
Member Author

Ok, I've updated this to remove the exposed ERR_ constructors for the expressed by both @targos and @joyeecheung ... I just don't think we're ready to make those constructors public and commit to an API contract for those yet. Everything else remains the same except that the documentation moves to util.md

@jasnell jasnell removed the needs-ci PRs that need a full CI run. label May 10, 2021
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Comment thread lib/util/errors.js Outdated
Comment thread lib/util/errors.js Outdated
Comment thread lib/util/errors.js Outdated
Comment thread lib/util/errors.js Outdated
@jasnell
jasnell force-pushed the add-util-errors branch from 0ce6341 to 82a8fd0 Compare May 12, 2021 19:07
@nodejs-github-bot

nodejs-github-bot commented May 12, 2021 •

Copy link
Copy Markdown
Collaborator

Exports a subset of `internal/errors` as `require('util/errors')`.

The reason for `util/errors` is because there is already a `errors`
module on npm that has a non-trivial number of downloads per week.

Signed-off-by: James M Snell <[email protected]>
@jasnell
jasnell force-pushed the add-util-errors branch from 82a8fd0 to 6148519 Compare May 12, 2021 19:55

@mcollina mcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

lgtm

@jasnell jasnell added author ready PRs with CI started, the required approvals, and no outstanding review comments. review wanted PRs that need review. labels May 13, 2021
@jasnell

jasnell commented May 13, 2021

Copy link
Copy Markdown
Member Author

@nodejs/tsc ... this needs another TSC review and sign off

Comment thread lib/util/errors.js
}
if (typeof message !== 'function' &&
typeof message !== 'string') {
throw new ERR_INVALID_ERROR_MESSAGE(code);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why not ERR_INVALID_ARG_TYPE ? It supports multiple types and is used almost everywhere else for this kind of error.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I realize message is not an arg here. Why is it only validated now rather than before adding it to the messages map?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please let me think a bit about the proposed API. There's something that doesn't feel right.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The API was designed with minimal changes to the internals in mind.

@ronag ronag left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@jasnell jasnell removed the review wanted PRs that need review. label May 13, 2021
@jasnell

jasnell commented May 13, 2021

Copy link
Copy Markdown
Member Author

Note to folks: While this has the sign off from the two TSC members necessary to land, @targos has requested more time to review it. Please do not land this PR until they've had a few days to complete their review.

@mhdawson

Copy link
Copy Markdown
Member

@james I'm wondering about the motivation/use case. Could you give us a 1 paragraph level description of the problem being solved, use case for the exposed APIs?

@jasnell

jasnell commented May 14, 2021

Copy link
Copy Markdown
Member Author

@mhdawson ... See https://github.com/fastify/fastify-error for an example use case motivating the api for creating the error classes.

Regarding the use case for exposing AbortError and DOMException, it comes down to consistency. We want users to make use of things like AbortSignal. It makes sense to make it easy for them to do so in a way that is consistent with core's use.

@mhdawson

Copy link
Copy Markdown
Member

@jasnell thanks, that helps :)

@targos targos self-assigned this May 17, 2021
@jasnell

jasnell commented May 17, 2021

Copy link
Copy Markdown
Member Author

@targos ... any further thoughts on this?

@targos

targos commented May 17, 2021

Copy link
Copy Markdown
Member

Sorry, I didn't find time to look at this during the long weekend. I'll do it first time tomorrow morning!

@BridgeAR BridgeAR left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I am not certain that we should really expose our makeErrorWithCode, even with a layer above abstracting it.

There's also at least one difference to our API: Our internals allow to define multiple error classes for the same error code. That is not possible with the new API.

If we really want to expose this, we should also document, that input is going to be validated while creating a new instance during runtime. The error being thrown at this point is going to point to Node.js though, that it's an implementation mistake on our side. This would from now on definitely be wrong and we would have to update that to throw something else instead. And if I am not mistaken, it's possible to create errors with identical codes that are already in use by e.g., Node.js. This is not ideal. I would also rather differentiate codes that are used by Node.js and ones that are created by libraries as we might add duplicate codes that way later on.

For these reasons I am currently against adding this to core.

@jasnell

jasnell commented May 19, 2021 •

Copy link
Copy Markdown
Member Author

There's also at least one difference to our API: Our internals allow to define multiple error classes for the same error code. That is not possible with the new API.

That was intentional to simplify the API a bit. There's nothing to stop the user code from defining multiple custom errors with separate types and the same code.

If we really want to expose this, we should also document, that input is going to be validated while creating a
new instance during runtime. The error being thrown at this point is going to point to Node.js though, that it's an implementation mistake on our side. This would from now on definitely be wrong and we would have to update that to throw something else instead.

That's fine. We can change the error that is thrown when this API is used.

And if I am not mistaken, it's possible to create errors with identical codes that are already in use by e.g., Node.js. This is not ideal. I would also rather differentiate codes that are used by Node.js and ones that are created by libraries as we might add duplicate codes that way later on.

I'm not convinced that's really a problem. What exactly could we do differently here that would make you +1?

@jasnell jasnell removed the author ready PRs with CI started, the required approvals, and no outstanding review comments. label May 20, 2021
@jasnell

jasnell commented May 20, 2021

Copy link
Copy Markdown
Member Author

Removed the author ready label while we get the objection resolved.

@DerekNonGeneric DerekNonGeneric left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Agreed that the code property is going to be subject to debate here.

Thanks for putting a hold on this PR for the time being. AFAICT, it does still seem to be half-baked.

Changing it up so that the error codes give us a way to know if the error came from Node.js internals or not seems smart.

@jasnell

jasnell commented May 24, 2021

Copy link
Copy Markdown
Member Author

@DerekNonGeneric @BridgeAR ... Ok, but I'm going to need a bit more detail in terms of what would be acceptable to you both here. It's clear that you don't want what the API currently does but it's not clear what you would want.

@mcollina

Copy link
Copy Markdown
Member

I would like to focus on the need for exposing an API to create errors with code, and leave out the current implementation to a later discussion.

Long time ago, we underwent a massive refactoring to add a code property to all Node.js errors. We did this change because developers relied on the .message property of errors, which lead to high unstable code. I believe this was an extremely useful addition to Node.js. I think we can all agree to the benefits of this, and if not please voice your concerns clearly.

As we have clarified that creating errors with a .code property is useful, we are limiting our users by not exposing a utility to do so themselves. They will need to implement their own system, if at all. I think we can promote a better pattern for the whole ecosystem by recommending them to add .code to their errors by exposing such an utility.
As an example, check out https://github.com/fastify/fastify-error.

The point of debate is if we agree something like this is worthwhile doing first and then figure out the best implementation and what to expose.

@mhdawson

Copy link
Copy Markdown
Member

I see value in helping to drive a common way to create/use the error code on Exceptions.

@mcollina, @jasnell what would the trade offs be between building into Node.js core versus a module a repo within the Node.js org? I expect there would be things like less code re-use, not being an official part of Node.js AP, etc in terms of promoting adoption but it would be good to get your takes on that.

@mcollina

Copy link
Copy Markdown
Member

I can coordinate moving https://github.com/fastify/fastify-error if we want to make it official.

My assumption is that we would link the module from the Node.js docs?

@mhdawson

Copy link
Copy Markdown
Member

If we moved it over I think referencing in the docs would make sense to me.

@jasnell

jasnell commented May 31, 2021

Copy link
Copy Markdown
Member Author

Going to go ahead and close this PR given that it likely won't be moving forward as is.

@jasnell jasnell closed this May 31, 2021
@mhdawson

Copy link
Copy Markdown
Member

@jasnell In #38575 (comment) I was just asking about different options but if moving into org satisfies the need from your perspective then seems like a reasonable way to move forward.

@targos targos removed their assignment Oct 31, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build Issues and PRs related to Node.js builds or CI infrastructure. semver-major PRs that contain breaking changes and should be released in the next major version.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make AbortError public errors.js module

10 participants