You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
InvalidArgumentError or invalid_argument is not a oauth2-error. It is used by oauth2-server to indicate errors like that specific internal implementation is wrong. E.g. Request is missing header. Also the HttpStatusCode of 500 clearly indicates that it is a ServerError and not something what the enduser can control.
Its actually scattered all over the place. It is everywhere used where an InternalServerError should be thrown because the implementor made an implementation error.
Revisiting this with a full census + serialization trace. The premise is half right, so I've opened a targeted PR rather than a blanket replacement.
invalid_argument is genuinely non-standard — it's in none of RFC 6749's error sets (§5.2 token endpoint; §4.1.2.1 / §4.2.2.1 authorization endpoint) nor the IANA registry. But of the ~56 InvalidArgumentError throw sites in lib/, ~32 are construction/config-time guards (missing model/options, model does not implement X(), request/response instance checks). Those throw synchronously out of constructors or before the handler try block, are handed straight back to the integrator, and never reach an OAuth client — there a descriptive invalid_argument is a useful developer signal, and the conformance objection simply doesn't apply.
The real defect is narrow. Both the token and authorize handler catch blocks only re-wrap if (!(e instanceof OAuthError)) as ServerError. Because InvalidArgumentError extends OAuthError, it slips through and gets serialized verbatim — updateErrorResponse sets error: error.name, so a request-time InvalidArgumentError reaches the client as error=invalid_argument with HTTP 500. The reachable sites:
a model returning malformed token data → TokenModel / BearerTokenType throw (lib/models/token-model.js, lib/token-types/bearer-token-type.js)
a model returning a falsy authorization code → CodeResponseType throws (lib/response-types/code-response-type.js)
Fix (#451): normalise InvalidArgumentError (like any other internal error) to ServerError at the serialisation boundary — so the wire reports a standard server_error/503, with the original preserved as .inner for server-side logs. The construction/config guards are untouched and still surface InvalidArgumentError to integrator code. This concentrates the change in the two catch blocks rather than rewriting 56 throw sites + ~14 test files.
This is breaking (the wire error/status for those runtime failures changes from invalid_argument/500 to server_error/503), so it targets the next major.
Activity
jankapunkt commentedon Nov 16, 2021
Please also add, which parts of the code are affected and which tests need to be updated.
Uzlopak commentedon Nov 16, 2021
Its actually scattered all over the place. It is everywhere used where an InternalServerError should be thrown because the implementor made an implementation error.
Uzlopak commentedon Nov 16, 2021
We could also just patch the InvalidArgumentError to extend ServerError or change invalid_argument to server_error.
dhensby commentedon Jun 17, 2026
Revisiting this with a full census + serialization trace. The premise is half right, so I've opened a targeted PR rather than a blanket replacement.
invalid_argumentis genuinely non-standard — it's in none of RFC 6749's error sets (§5.2 token endpoint; §4.1.2.1 / §4.2.2.1 authorization endpoint) nor the IANA registry. But of the ~56InvalidArgumentErrorthrow sites inlib/, ~32 are construction/config-time guards (missingmodel/options,model does not implement X(),request/responseinstance checks). Those throw synchronously out of constructors or before the handlertryblock, are handed straight back to the integrator, and never reach an OAuth client — there a descriptiveinvalid_argumentis a useful developer signal, and the conformance objection simply doesn't apply.The real defect is narrow. Both the token and authorize handler catch blocks only re-wrap
if (!(e instanceof OAuthError))asServerError. BecauseInvalidArgumentError extends OAuthError, it slips through and gets serialized verbatim —updateErrorResponsesetserror: error.name, so a request-timeInvalidArgumentErrorreaches the client aserror=invalid_argumentwith HTTP 500. The reachable sites:TokenModel/BearerTokenTypethrow (lib/models/token-model.js,lib/token-types/bearer-token-type.js)CodeResponseTypethrows (lib/response-types/code-response-type.js)Fix (#451): normalise
InvalidArgumentError(like any other internal error) toServerErrorat the serialisation boundary — so the wire reports a standardserver_error/503, with the original preserved as.innerfor server-side logs. The construction/config guards are untouched and still surfaceInvalidArgumentErrorto integrator code. This concentrates the change in the two catch blocks rather than rewriting 56 throw sites + ~14 test files.This is breaking (the wire
error/status for those runtime failures changes frominvalid_argument/500 toserver_error/503), so it targets the next major.