awslabs/llrt · error · AssertionError

expected promise to throw an error, but it didn't

Error message

expected promise to throw an error, but it didn't

What it means

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.

Solutions

  1. Make sure you pass the promise itself (or a thunk), not its result, and that it actually rejects: throw new Error(...) or Promise.reject(...).
  2. Confirm the code under test still raises for this input; update the test if behavior legitimately changed.
  3. If you expected success, use await expect(p).resolves.to... instead of rejects.
  4. Check that a catch/try in the code under test isn't swallowing the intended rejection.

Example fix

// before (fetchUser returns instead of throwing on 404)
await expect(fetchUser(-1)).rejects.toThrow();
// after (ensure the function rejects)
if (!res.ok) throw new Error('user not found');
await expect(fetchUser(-1)).rejects.toThrow();
Defensive patterns

Strategy: try-catch

Validate before calling

// assert the promise can reject before testing
let didReject = false; try { await p; } catch { didReject = true; } if (!didReject) throw new Error('fixture must reject');

Try / catch

try { await expect(p).rejects.toThrow('expected message'); } catch (e) { /* promise resolved unexpectedly — inspect p and code under test */ }

Prevention

When it happens

Trigger: await expect(somePromise).rejects.toThrow() (or .toThrowError) where somePromise resolves successfully instead of rejecting; message can be overridden via the expect message flag.

Common situations: 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.

Related errors


AI-assisted analysis of awslabs/llrt@742fc00b82 (2026-09-12). Data as JSON: /api/errors/24823015b68cca2b. Report an issue: GitHub.

Appendix: source

Thrown at llrt_core/src/modules/js/@llrt/expect/jest-expect.ts:92

        const object = utils.flag(this, "object");
        const isNot = utils.flag(this, "negate") as boolean;
        if (promise === "rejects") {
          utils.flag(this, "object", () => {
            throw object;
          });
        }
        // if it got here, it's already resolved
        // unless it tries to resolve to a function that should throw
        // called as '.resolves[.not].toThrow()`
        else if (promise === "resolves" && typeof object !== "function") {
          if (!isNot) {
            const message =
              utils.flag(this, "message") ||
              "expected promise to throw an error, but it didn't";
            const error = {
              showDiff: false,
            };
            throw new AssertionError(message, error, utils.flag(this, "ssfi"));
          } else {
            return;
          }
        }
        _super.apply(this, args);
      };
    });
  });

  def("toEqual", function (expected) {
    const actual = utils.flag(this, "object");
    const equal = jestEquals(actual, expected, [
      ...customTesters,
      iterableEquality,
    ]);
    return this.assert(
      equal,
      "expected #{this} to deeply equal #{exp}",

View on GitHub (pinned to 742fc00b82)