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
{{ message }}
Repository navigation
Vitest False Positive in PR Added in-memory locks for the process, fix for Bug #2579 temporary measure. #3060 #3073
Vitest reports an “Unhandled Errors” warning for a test that intentionally throws an error ("should throw error for non-existent entity").
The test itself passes correctly using .rejects.toThrow(), but Vitest incorrectly surfaces the expected rejection as an unhandled error.
This causes the TypeScript / Test memory CI job to fail even though there is no bug in the memory server implementation.
To Reproduce
Steps to reproduce the behavior:
Run the memory server tests using:
pnpm test:memory
Look for the test:
"should throw error for non-existent entity"
Observe that the test passes but Vitest outputs an “Unhandled Errors” warning.
In GitHub Actions, this warning results in a failing test job.
Expected behavior
Vitest should correctly treat .rejects.toThrow() as a handled and expected error, and should not report the intentionally thrown error as an unhandled rejection.
CI should pass when the test succeeds, without false-positive warnings.
Logs
Example output:
Unhandled Errors:
❯ Error: Entity does not exist
at ...
The test reports PASS
The warning appears only in the "Unhandled Errors" summary
No runtime errors or implementation failures occur
Additional context
This behavior is a Vitest testing quirk, not a bug in the memory server code.
All locking, file serialization, and race condition tests pass successfully.
The new lock implementation is functioning as expected.
The false warning appears because Vitest sometimes logs expected async errors as “unhandled” even when wrapped in .rejects.toThrow().
Possible mitigations (optional):
Rewrite the test using assert.rejects(...)
Wrap error tests to avoid Vitest’s unhandled rejection reporting
Add scoped process.on("unhandledRejection", () => {}); for this file (not recommended except for CI cleanliness)
If you want, I can also rewrite the test file for a clean CI run.
Hey! I ran into a similar pattern in our bug knowledge base and thought this might help.
What's happening: Vitest's global unhandled rejection handler captures the Promise rejection before .rejects.toThrow() can assert on it. This happens because the async function throws synchronously inside the Promise executor, and Vitest's error tracking hooks see the rejection before the test framework's .rejects wrapper can intercept it. The in-memory lock PR (#3060) added a test that calls a method expected to throw for a non-existent entity, but the thrown error propagates to Node's unhandledRejection event before Vitest's .rejects.toThrow() matcher resolves.
What worked for us:
Wrap the expected-to-throw call in a try/catch block inside the test instead of relying on .rejects.toThrow(), or use expect(async () => { await call(); }).rejects.toThrow() with an explicit await on the outer expect. Alternatively, if the method under test throws synchronously (not returning a rejected Promise), use expect(() => call()).toThrow() without .rejects. Another approach is to add a Vitest config option to suppress unhandled rejection warnings for known test patterns.
Steps:
Identify the failing test in the memory server test file (likely src/memory/tests or similar path) that uses .rejects.toThrow() for the 'non-existent entity' case
Option A: Change from expect(promise).rejects.toThrow() to await expect(async () => { await methodCall(); }).rejects.toThrow('Entity does not exist') — ensuring the outer expect is properly awaited
Option B: Wrap in try/catch: try { await methodCall(); expect.unreachable(); } catch (e) { expect(e.message).toBe('Entity does not exist'); }
Option C: If the function throws synchronously before returning a Promise, use expect(() => methodCall()).toThrow() without .rejects
Verify CI passes by running pnpm test:memory locally and confirming no 'Unhandled Errors' warning appears
// Before (causes Vitest false positive unhandled rejection):
it('should throw error for non-existent entity', async () => {
await expect(server.getEntity('nonexistent')).rejects.toThrow('Entity does not exist');
});
// After (Option A - properly awaited async closure):
it('should throw error for non-existent entity', async () => {
await expect(async () => {
await server.getEntity('nonexistent');
}).rejects.toThrow('Entity does not exist');
});
// After (Option B - try/catch, most reliable):
it('should throw error for non-existent entity', async () => {
try {
await server.getEntity('nonexistent');
expect.unreachable('Should have thrown');
} catch (e) {
expect((e as Error).message).toBe('Entity does not exist');
}
});
📊 We found 1 similar case in our knowledge base with the same pattern — this gives us medium confidence in this analysis.
Hope this helps! Let me know if it doesn't match your case — happy to dig deeper. 🦞
Disclosure: This analysis is from Confucius Debug, an AI-powered community KB for agent bugs. Please verify before applying.
🦞 Confucius Debug — community knowledge base for AI agent bugs. Free to search via MCP.
Activity
sstklen commentedon Feb 25, 2026
Hey! I ran into a similar pattern in our bug knowledge base and thought this might help.
What's happening: Vitest's global unhandled rejection handler captures the Promise rejection before .rejects.toThrow() can assert on it. This happens because the async function throws synchronously inside the Promise executor, and Vitest's error tracking hooks see the rejection before the test framework's .rejects wrapper can intercept it. The in-memory lock PR (#3060) added a test that calls a method expected to throw for a non-existent entity, but the thrown error propagates to Node's unhandledRejection event before Vitest's .rejects.toThrow() matcher resolves.
What worked for us:
Wrap the expected-to-throw call in a try/catch block inside the test instead of relying on .rejects.toThrow(), or use expect(async () => { await call(); }).rejects.toThrow() with an explicit await on the outer expect. Alternatively, if the method under test throws synchronously (not returning a rejected Promise), use expect(() => call()).toThrow() without .rejects. Another approach is to add a Vitest config option to suppress unhandled rejection warnings for known test patterns.
Steps:
expect(promise).rejects.toThrow()toawait expect(async () => { await methodCall(); }).rejects.toThrow('Entity does not exist')— ensuring the outer expect is properly awaitedtry { await methodCall(); expect.unreachable(); } catch (e) { expect(e.message).toBe('Entity does not exist'); }expect(() => methodCall()).toThrow()without .rejectspnpm test:memorylocally and confirming no 'Unhandled Errors' warning appears📊 We found 1 similar case in our knowledge base with the same pattern — this gives us medium confidence in this analysis.
Hope this helps! Let me know if it doesn't match your case — happy to dig deeper. 🦞
🦞 Confucius Debug — community knowledge base for AI agent bugs. Free to search via MCP.
fix(memory): resolve Vitest false positive for expected rejection
fix(memory): resolve Vitest false positive for expected rejection (mo…
olaservo commentedon Sep 2, 2026
Fixed by #3893, which wraps the assertion in an async closure so the expected rejection is scoped to the
expectchain. Closing.