denoland/deno · error · TypeError
ERR_INVALID_ARG_VALUE
ERR_INVALID_ARG_VALUE
Error message
The argument 'tracked' is not a tracked function. Received ${inspected} What it means
CallTracker wraps each function passed to tracker.calls(fn, expected) in a tracking context stored in an internal WeakMap. reset(tracked) and getCalls(tracked) look the argument up in that map; an argument that was never registered — most commonly the original fn instead of the wrapper calls() returns — throws ERR_INVALID_ARG_VALUE with 'is not a tracked function'.
Source
Thrown at ext/node/polyfills/internal/assert/calltracker.js:87
`executed ${this.#calls.length} time(s).`;
return {
message,
actual: this.#calls.length,
expected: this.#expected,
operator: this.#name,
stack: this.#stackTrace,
};
}
}
}
class CallTracker {
#callChecks = new SafeSet();
#trackedFunctions = new SafeWeakMap();
#getTrackedFunction(tracked) {
if (!this.#trackedFunctions.has(tracked)) {
throw new ERR_INVALID_ARG_VALUE(
"tracked",
tracked,
"is not a tracked function",
);
}
return this.#trackedFunctions.get(tracked);
}
reset(tracked) {
if (tracked === undefined) {
SetPrototypeForEach(this.#callChecks, (check) => check.reset());
return;
}
this.#getTrackedFunction(tracked).reset();
}
getCalls(tracked) {View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Always keep the return value of tracker.calls(fn) and pass that wrapper to getCalls()/reset().
- Reassign in place — fn = tracker.calls(fn) — so every later reference is the tracked one.
- Consider node:test's mock module (mock.fn / mock.method) — CallTracker is deprecated in modern Node.
Example fix
// before tracker.calls(handleRequest); // wrapper discarded handleRequest(req, res); // calls original: nothing recorded tracker.getCalls(handleRequest); // ERR_INVALID_ARG_VALUE: not a tracked function // after const handleTracked = tracker.calls(handleRequest); handleTracked(req, res); tracker.getCalls(handleTracked); // recorded call arguments
Defensive patterns
Strategy: validation
Validate before calling
const trackedFns = new WeakSet();
function track(tracker, fn, expected = 1) {
const wrapped = tracker.calls(fn, expected);
trackedFns.add(wrapped);
return wrapped;
}
function isTracked(fn) {
return trackedFns.has(fn);
}
// before tracker.getCalls(x): if (!isTracked(x)) throw new Error('untracked fn'); Try / catch
try {
tracker.getCalls(fn);
} catch (e) {
if (e.code === 'ERR_INVALID_ARG_VALUE' && /tracked function/.test(e.message)) {
// re-wrap fn with tracker.calls and use the returned wrapper
} else throw e;
} Prevention
- Treat tracker.calls() as returning the new handle — always store and use it.
- Reassign in place (fn = tracker.calls(fn)) so all call sites use the wrapper.
- Prefer node:test mock.fn()/mock.method() over the deprecated CallTracker.
When it happens
Trigger: tracker.getCalls(fn) or tracker.reset(fn) where fn was never wrapped — e.g. const wrapped = tracker.calls(fn); tracker.getCalls(fn); (original fn passed instead of the wrapper). Passing a function registered on a different CallTracker instance, or the pre-wrap reference kept alive by a refactor, produces the same throw.
Common situations: Refactors that keep a reference to the pre-wrap function; passing a function wrapped by a different tracker instance; asserting on the wrong export of a module.
Related errors
- ERR_UNAVAILABLE_DURING_EXIT
- ERR_ASSERTION
- ERR_ASSERTION
- ERR_INVALID_OBJECT_DEFINE_PROPERTY
- ERR_CONSTRUCT_CALL_REQUIRED
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/7f8f1a0ed6a1265c.
Report an issue: GitHub.