Skip to content

feat(ses): add support for "code" prop in SES-managed Errors#3130

Open
boneskull wants to merge 2 commits intomasterfrom
boneskull/error-code
Open

feat(ses): add support for "code" prop in SES-managed Errors#3130
boneskull wants to merge 2 commits intomasterfrom
boneskull/error-code

Conversation

@boneskull
Copy link
Member

  • Adds a new string option to AssertMakeErrorOptions, code
  • If a string, will be an non-enumerable property of the Error instance returned by makeError.
  • To avoid mutating global types, a new type SesError is introduced which is simply Error & {code?: string}.

Note that code is expected to be a string here, but only by convention; the language will not enforce this (as per the below proposal).

Ref: https://github.com/tc39-transfer/proposal-error-code-property

@changeset-bot
Copy link

changeset-bot bot commented Mar 17, 2026

⚠️ No Changeset found

Latest commit: bf477a0

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@boneskull boneskull requested review from erights and gibson042 March 17, 2026 03:26
@boneskull boneskull self-assigned this Mar 17, 2026
@boneskull boneskull added the enhancement New feature or request label Mar 17, 2026
@boneskull boneskull requested review from kriskowal and naugtur March 17, 2026 03:26
@boneskull
Copy link
Member Author

boneskull commented Mar 17, 2026

What I'd really like to see here is a makeError which is generic on the error constructor type (so that it would return a value of that type), but the signature is such that it is not possible--the default parameter of globalThis.Error creates a type error when it's generic, and removing the default value is invalid syntax (since the previous message/details parameter also has a default value).

const makeError = (
optDetails = redactedDetails`Assert failed`,
errConstructor = globalThis.Error,
{
errorName = undefined,
cause = undefined,
errors = undefined,
sanitize = true,
code = undefined,
} = {},
) => {
// Promote string-valued `optDetails` into a minimal DetailsParts

The workaround is to just wrap makeError in another function.

@boneskull boneskull force-pushed the boneskull/error-code branch from e6d46c7 to 0b2ff5a Compare March 17, 2026 03:32
/**
* An `Error` with a `code` property.
*/
export type SesError = Error & { code?: string };
Copy link
Member Author

Choose a reason for hiding this comment

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

Open to naming suggestions

Copy link
Member Author

Choose a reason for hiding this comment

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

(We could have used module augmentation to extend the global Error interface with a code?: string prop, but that would affect all downstream consumers of ses, which would be inconsiderate)

Copy link
Contributor

Choose a reason for hiding this comment

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

Under any name, I don't like introducing a new type for this purpose if possible.

What about cause and errors? Do they have this problem too? If not, can we treat code the same way? Once we support SuppressedError (hopefully soon) we will also need to support the further instance properties error and suppressed.

Copy link
Member

@kriskowal kriskowal left a comment

Choose a reason for hiding this comment

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

Needs changeset and consensus on names.

/**
* An `Error` with a `code` property.
*/
export type SesError = Error & { code?: string };
Copy link
Member

Choose a reason for hiding this comment

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

Consider CodedError (imprecise) or OptionallyCodedError (ew) or MaybeCodedError (ew but less so) or ErrorConCodé (facetious) or CodableError (getting there, leaves air for CodedError to require the code) since this isn’t particularly intrinsic to SES.

type CodedError = Error & { code: string };
type CodableError = Error & {code?: string };

Could be that we overload these functions so that CodedError is implied by presence of code option.

Copy link
Member Author

@boneskull boneskull Mar 17, 2026

Choose a reason for hiding this comment

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

"Codeträger?" "Fehlercodetragendesding?" "Codebesitzend" really rolls off the tongue

Copy link
Member Author

Choose a reason for hiding this comment

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

Going w/ CodableError. 🐟

- Adds a new `string` option to `AssertMakeErrorOptions`, `code`
- If a `string`, will be an non-enumerable property of the `Error` instance returned by `makeError`.
- To avoid mutating global types, a new type `SesError` is introduced which is simply `Error & {code?: string}`.

Note that `code` is expected to be a `string` here, but only by convention; the language will not enforce this (as per the below proposal).

Ref: https://github.com/tc39-transfer/proposal-error-code-property
has nothing to do with fish
@boneskull boneskull force-pushed the boneskull/error-code branch from c58a919 to bf477a0 Compare March 17, 2026 23:34
* such as `stack` on v8 (Chrome, Brave, Edge?)
* - `sanitizeError` will freeze the error, preventing any correct engine from
* adding or
* altering any of the error's own properties `sanitizeError` is done.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* altering any of the error's own properties once `sanitizeError` is done.

This was my mistake, but might as well add as a drive-by to this PR is you don't mind.

});
}
}
if (code !== undefined && typeof code === 'string') {
Copy link
Contributor

@erights erights Mar 21, 2026

Choose a reason for hiding this comment

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

Here, there's no good answer for "what do to if code is not a string?". Rather, I think that here, following the proposal, you should not filter by the value of code. Rather, put this value test above in sanitizeError. There, if you see a non-string code, delete it and add it to droppedDetails so that it is hidden but shows up as a diagnostic on console output.

/**
* An `Error` with a `code` property.
*/
export type SesError = Error & { code?: string };
Copy link
Contributor

Choose a reason for hiding this comment

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

Under any name, I don't like introducing a new type for this purpose if possible.

What about cause and errors? Do they have this problem too? If not, can we treat code the same way? Once we support SuppressedError (hopefully soon) we will also need to support the further instance properties error and suppressed.

@erights
Copy link
Contributor

erights commented Mar 21, 2026

See also DRAFT PRs #2223 and #2429 . Like them, we need to coordinate this change with @endo/pass-style and @endo/marshal so that .code is actually passed. Doesn't need to happen in this PR, but that is my preference since it should be a coordinated change. Please borrow as much as you like from those other draft PRs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants