Skip to content

Conversation

@kanej
Copy link
Member

@kanej kanej commented Nov 27, 2025

This fix for #7722 is still in the investigation stage. The issue is that a missing async await against our mocha assertions can lead to an invariant error - we would prefer a clear message suggesting that an await is missing.

This PR adds an example project that replicates the error, to run it:

cd v-next/example-project-assertion
pnpm install
pnpm hardhat test mocha

# No contracts to compile

# Running Mocha tests


#   Hardhat3 test
#     ✔ Should transfer money to another wallet with extra value (331ms)

# Unhandled promise rejection:

# HardhatError: HHE100: An internal invariant was violated: The block doesn't exist
#     at assertHardhatInvariant (/workspaces/hardhat/v-next/hardhat-errors/src/errors.ts:237:11)
#     at getBalanceChange (/workspaces/hardhat/v-next/hardhat-ethers-chai-matchers/src/internal/matchers/changeEtherBalance.ts:100:3)
#     at async Promise.all (index 0)

Investigation status

My current hypothesis is that the lack of an await, means that some lower layer is closed or cleaned up. When the assertion expect(txn).to.changeEtherBalance(ethers, alice, 10) is run, the test has already completed, so the calls to the in-memory EDR network connection fail, ethers returns null for the block number and so we get the invariant exception above (but also a passing test).

My guess was that the EDR connection was giving some odd error rather than a connection closed when ethers called getBlock, and was then falling back on null. However, closing the connection leads to a connection closed error, see:

https://github.com/NomicFoundation/hardhat/blob/7b335f9a64b46715b9db9082ff16bbe2cf95fc81/v-next/example-project-assertion/scripts/test-closed-connection.ts

Next steps

Resolve the mechanism that leads ethers to return null for getBlock. Has the underlying connection been cleaned up with the completion of the test or is it some other reason? Setting up debugging is my next move.

Adds another example project under v-next to allow replicating the
issue.
@changeset-bot
Copy link

changeset-bot bot commented Nov 27, 2025

⚠️ No Changeset found

Latest commit: c14f4ff

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions
Copy link
Contributor

hardhat

Total size of the bundle: 240M
Total number of dependencies (including transitive): 47

List of dependencies (sorted by size)
234M	total
37M	@nomicfoundation/edr-linux-x64-musl
36M	@nomicfoundation/edr-linux-x64-gnu
33M	@nomicfoundation/edr-linux-arm64-musl
33M	@nomicfoundation/edr-linux-arm64-gnu
24M	@nomicfoundation/edr-win32-x64-msvc
24M	@nomicfoundation/edr-darwin-x64
21M	@nomicfoundation/edr-darwin-arm64
7.3M	@sentry/core
5.2M	zod
2.7M	micro-eth-signer
1.9M	@noble/curves
1.7M	undici
1.2M	@noble/hashes
1020K	@nomicfoundation/hardhat-utils
864K	@streamparser/json
624K	micro-packed
592K	tsx
552K	@nomicfoundation/hardhat-errors
492K	@scure/bip39
464K	@nomicfoundation/edr
448K	fast-equals
408K	json-stream-stringify
368K	ethereum-cryptography
332K	@streamparser/json-node
320K	enquirer
320K	@nomicfoundation/hardhat-zod-utils
288K	semver
200K	ws
180K	chokidar
176K	get-tsconfig
168K	@scure/base
160K	esbuild
136K	adm-zip
96K	@scure/bip32
92K	chalk
72K	@nomicfoundation/solidity-analyzer
68K	debug
60K	readdirp
56K	rfdc
48K	ansi-colors
44K	resolve.exports
40K	resolve-pkg-maps
36K	p-map
24K	strip-ansi
24K	env-paths
24K	ansi-regex
20K	ms

@kanej kanej changed the title chore: add reproducible example chore: add reproducible example of mocha missing async warning Nov 27, 2025
@zoeyTM
Copy link
Contributor

zoeyTM commented Dec 8, 2025

After further investigation, I have found that this issue appears to be due to the garbage collector cleaning up the in-use NetworkConnectionImplementation instance inside hardhat's network manager, specifically this section:

/* Capture the hook manager in a local variable to avoid retaining a
reference to the NetworkManager instance, allowing the garbage collector
to clean up the NetworkConnectionImplementation instances properly. */
const hookManager = this.#hookManager;
const createProvider = async (
networkConnection: NetworkConnectionImplementation<ChainTypeT>,
): Promise<EthereumProvider> => {
const jsonRpcRequestWrapper: JsonRpcRequestWrapperFunction = (
request,
defaultBehavior,
) =>
hookManager.runHandlerChain(
"network",
"onRequest",
[networkConnection, request],
async (_context, _connection, req) => defaultBehavior(req),
);

The local variable on line 179 does appear to serve its intended purpose according to the comment above it, however when the handler chain is run on line 188, inside the chains delayed execution is where the strange error is being thrown.

Removing the local variable on line 179 or changing line 188 to invoke this.#hookManager.runHandlerChain directly instead of via the local variable; either of these options will independently fix the problem and the error will not be shown when running the tests in the reproducible example. I'm unsure if that is a solution we are happy with as we would lose the garbage collector inefficiencies mentioned in the comment, but those solutions do at least serve as evidence of where exactly the problem lies.

@michalbrabec michalbrabec linked an issue Jan 12, 2026 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve error message when no await in chai matchers

2 participants