{"record":{"id":"c6d98b9e195d54d3","repo":"vitest-dev/vitest","slug":"expected-function-to-throw-an-error-but-it-didn-t","errorCode":null,"errorMessage":"expected function to throw an error, but it didn't","messagePattern":"expected function to throw an error, but it didn't","errorType":"exception","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"packages/expect/src/jest-expect.ts","lineNumber":802,"sourceCode":"      }\n      else {\n        let isThrow = false\n        try {\n          obj()\n        }\n        catch (err) {\n          isThrow = true\n          thrown = err\n        }\n\n        if (!isThrow && !isNot) {\n          const message\n            = utils.flag(this, 'message')\n              || 'expected function 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        }\n      }\n\n      if (typeof expected === 'function') {\n        const name = expected.name || expected.prototype.constructor.name\n        return this.assert(\n          thrown && thrown instanceof expected,\n          `expected error to be instance of ${name}`,\n          `expected error not to be instance of ${name}`,\n          expected,\n          thrown,\n        )\n      }\n\n      if (isError(expected)) {\n        const equal = jestEquals(thrown, expected, [\n          ...customTesters,\n          iterableEquality,","sourceCodeStart":784,"sourceCodeEnd":820,"githubUrl":"https://github.com/vitest-dev/vitest/blob/1fa9837ec26533512fdcad8baebf249771bd340a/packages/expect/src/jest-expect.ts#L784-L820","documentation":"Thrown by `toThrow`/`toThrowError` when the subject function ran to completion without raising. The matcher invokes the function, and if `isThrow` stays false (and `.not` is not set), it raises `AssertionError`. This is the core failure path for a negative `toThrow`.","triggerScenarios":"Calling `expect(fn).toThrow()` on a function that does not throw; expecting a specific error but the code path skipped the throw branch (e.g. guarded by a condition that was false).","commonSituations":"Writing the test before the error path exists; condition guarding the throw was satisfied so the branch was skipped; the function swallowed errors internally with try/catch.","solutions":["Make the test inputs force the error branch (pass invalid arguments, set failing state).","If the function legitimately should not throw, remove the `toThrow` assertion or invert with `.not.toThrow()`.","Ensure internal try/catch does not swallow the error before it propagates."],"exampleFix":"// before\nexpect(() => validate('')).toThrow()\n// validate returns silently\n\n// after\nexpect(() => validate('')).toThrow('required')\n// after fixing validate to throw on empty input","handlingStrategy":"validation","validationCode":"let threw = false\ntry { fn() } catch { threw = true }\nif (!threw) { throw new Error('setup did not produce a throw') }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Drive the test inputs through the branch that throws.","Avoid swallowing errors inside the SUT before they propagate.","Write the test against the real failure path before asserting on it."],"tags":["expect","to-throw","assertion","jest-expect"],"backgroundTag":null,"analyzedSha":"1fa9837ec26533512fdcad8baebf249771bd340a","analyzedAt":"2026-08-11T16:11:39.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}