{"record":{"id":"24823015b68cca2b","repo":"awslabs/llrt","slug":"expected-promise-to-throw-an-error-but-it-didn-t","errorCode":null,"errorMessage":"expected promise to throw an error, but it didn't","messagePattern":"expected promise to throw an error, but it didn't","errorType":"exception","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"llrt_core/src/modules/js/@llrt/expect/jest-expect.ts","lineNumber":92,"sourceCode":"        const object = utils.flag(this, \"object\");\n        const isNot = utils.flag(this, \"negate\") as boolean;\n        if (promise === \"rejects\") {\n          utils.flag(this, \"object\", () => {\n            throw object;\n          });\n        }\n        // if it got here, it's already resolved\n        // unless it tries to resolve to a function that should throw\n        // called as '.resolves[.not].toThrow()`\n        else if (promise === \"resolves\" && typeof object !== \"function\") {\n          if (!isNot) {\n            const message =\n              utils.flag(this, \"message\") ||\n              \"expected promise to throw an error, but it didn't\";\n            const error = {\n              showDiff: false,\n            };\n            throw new AssertionError(message, error, utils.flag(this, \"ssfi\"));\n          } else {\n            return;\n          }\n        }\n        _super.apply(this, args);\n      };\n    });\n  });\n\n  def(\"toEqual\", function (expected) {\n    const actual = utils.flag(this, \"object\");\n    const equal = jestEquals(actual, expected, [\n      ...customTesters,\n      iterableEquality,\n    ]);\n    return this.assert(\n      equal,\n      \"expected #{this} to deeply equal #{exp}\",","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/awslabs/llrt/blob/742fc00b82cbeaab1c1b76f0d706c302a5cbc306/llrt_core/src/modules/js/@llrt/expect/jest-expect.ts#L74-L110","documentation":"In the async (promise) path of toThrow/toThrowError, when the awaited promise resolves without rejecting, the library throws this AssertionError to fail the test, unless the negated flag is set (then it returns). It means your promise should have rejected but fulfilled.","triggerScenarios":"await expect(somePromise).rejects.toThrow() (or .toThrowError) where somePromise resolves successfully instead of rejecting; message can be overridden via the expect message flag.","commonSituations":"Testing that invalid input rejects a promise but the code was fixed/changed to handle it gracefully; asserting on the wrong promise (e.g. forgetting to call an async function); mocking that swallows the rejection.","solutions":["Make sure you pass the promise itself (or a thunk), not its result, and that it actually rejects: throw new Error(...) or Promise.reject(...).","Confirm the code under test still raises for this input; update the test if behavior legitimately changed.","If you expected success, use await expect(p).resolves.to... instead of rejects.","Check that a catch/try in the code under test isn't swallowing the intended rejection."],"exampleFix":"// before (fetchUser returns instead of throwing on 404)\nawait expect(fetchUser(-1)).rejects.toThrow();\n// after (ensure the function rejects)\nif (!res.ok) throw new Error('user not found');\nawait expect(fetchUser(-1)).rejects.toThrow();","handlingStrategy":"try-catch","validationCode":"// assert the promise can reject before testing\nlet didReject = false; try { await p; } catch { didReject = true; } if (!didReject) throw new Error('fixture must reject');","typeGuard":null,"tryCatchPattern":"try { await expect(p).rejects.toThrow('expected message'); } catch (e) { /* promise resolved unexpectedly — inspect p and code under test */ }","preventionTips":["Always use .rejects for promise rejection assertions","Ensure the code under test throws/rejects on invalid input","Don't add .catch that swallows rejections","Pass the promise/thunk, not the awaited result"],"tags":["testing","promises","assertion","async"],"backgroundTag":"expected-promise-rejection-missing","analyzedSha":"742fc00b82cbeaab1c1b76f0d706c302a5cbc306","analyzedAt":"2026-09-12T11:14:07.838Z","contentChangedAt":"2026-09-12T11:14:07.838Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}