{"record":{"id":"e32f3567300f3907","repo":"avajs/ava","slug":"message-e32f35","errorCode":null,"errorMessage":"{message}","messagePattern":"\\{message\\}","errorType":"exception","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"lib/assert.js","lineNumber":533,"sourceCode":"\n\t\t\t\tpending(intermediate, assertionStack);\n\t\t\t\treturn intermediate;\n\t\t\t};\n\n\t\t\tif (isPromise(thrower)) {\n\t\t\t\treturn handlePromise(thrower, false);\n\t\t\t}\n\n\t\t\tlet retval;\n\t\t\tlet actual = null;\n\t\t\ttry {\n\t\t\t\tretval = thrower();\n\t\t\t} catch (error) {\n\t\t\t\tactual = error;\n\t\t\t}\n\n\t\t\tif (actual) {\n\t\t\t\tthrow fail(new AssertionError(message, {\n\t\t\t\t\tassertion: 't.throwsAsync()',\n\t\t\t\t\tcause: actual,\n\t\t\t\t\tformattedDetails: [formatWithLabel('Function threw synchronously. Use `t.throws()` instead:', actual)],\n\t\t\t\t}));\n\t\t\t}\n\n\t\t\tif (isPromise(retval)) {\n\t\t\t\treturn handlePromise(retval, true);\n\t\t\t}\n\n\t\t\tthrow fail(new AssertionError(message, {\n\t\t\t\tassertion: 't.throwsAsync()',\n\t\t\t\tformattedDetails: [formatWithLabel('Function returned:', retval)],\n\t\t\t}));\n\t\t});\n\n\t\tthis.notThrows = withSkip((fn, message) => {\n\t\t\tassertMessage(message, 't.notThrows()');","sourceCodeStart":515,"sourceCodeEnd":551,"githubUrl":"https://github.com/avajs/ava/blob/bbfd946322fdeca2b547a691d947fb4e18c0c67f/lib/assert.js#L515-L551","documentation":"In AVA, t.throwsAsync() expects a function that returns a promise (or a promise itself) which should reject. This AssertionError is thrown when the function throws synchronously instead of returning a rejecting promise. AVA detects the sync throw inside the try/catch around retval = thrower() and fails the assertion, suggesting you use t.throws() instead.","triggerScenarios":"Calling t.throwsAsync(() => { throw new Error('x'); }) where the callback throws before returning a promise; passing a sync-throwing wrapper around an async API; calling an async API that validates arguments synchronously and throws before creating its promise.","commonSituations":"Testing functions that are actually synchronous (misremembering which API is async); argument-validation in a function that throws before any promise is created; refactoring a sync function to async or vice versa and not updating the assertion.","solutions":["If the function throws synchronously, switch the assertion to t.throws(fn)","Wrap the sync-throwing call so it returns a rejected promise, e.g. t.throwsAsync(async () => fn())","Verify the function under test is genuinely async and returns a promise"],"exampleFix":"// before\nt.throwsAsync(() => parseConfig(bad), {instanceOf: SyntaxError});\n// after\n// parseConfig throws synchronously, so use:\nt.throws(() => parseConfig(bad), {instanceOf: SyntaxError});","handlingStrategy":"validation","validationCode":"function isAsyncThrowingCandidate(fn) {\n  return typeof fn === 'function';\n}\n// Prefer asserting sync throws directly:\n// if (doesThrowSync(fn)) t.throws(fn); else await t.throwsAsync(fn);","typeGuard":"const returnsPromise = (value) =>\n  typeof value === 'object' && value !== null && typeof value.then === 'function';","tryCatchPattern":"try {\n  await t.throwsAsync(fn, {instanceOf: MyError});\n} catch (e) {\n  if (/threw synchronously/.test(e.message)) t.throws(fn);\n  else throw e;\n}","preventionTips":["Match the assertion variant to whether the code is sync (t.throws) or async (t.throwsAsync)","Know your API: argument validation often throws before a promise exists","Add a quick unit check that the function under test returns a promise"],"tags":["ava","assertion","async","throws"],"backgroundTag":"throws-async-sync-throw","analyzedSha":"bbfd946322fdeca2b547a691d947fb4e18c0c67f","analyzedAt":"2026-09-02T01:24:43.834Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}