angular/angular-cli · error · Error
Argument ${isNonPrimitive(arg) ? arg.toString() : arg} is JS
Error message
Argument ${isNonPrimitive(arg) ? arg.toString() : arg} is JSON serializable. What it means
`memoize` builds its cache key with `JSON.stringify(args)`, so every argument must be JSON-serializable. Before calling the wrapped function it checks each argument with `isJSONSerializable` and throws this error for any non-serializable argument. (The message text reads 'is JSON serializable' but the intent is that the argument must be.)
Source
Thrown at packages/angular/cli/src/utilities/memoize.ts:29
*
* **Note**: Be cautious where and how to use this decorator as the size of the cache will grow unbounded.
*
* @see https://en.wikipedia.org/wiki/Memoization
*/
export function memoize<This, Args extends unknown[], Return>(
target: (this: This, ...args: Args) => Return,
context: ClassMemberDecoratorContext,
) {
if (context.kind !== 'method' && context.kind !== 'getter') {
throw new Error('Memoize decorator can only be used on methods or get accessors.');
}
const cache = new Map<string, Return>();
return function (this: This, ...args: Args): Return {
for (const arg of args) {
if (!isJSONSerializable(arg)) {
throw new Error(
`Argument ${isNonPrimitive(arg) ? arg.toString() : arg} is JSON serializable.`,
);
}
}
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key) as Return;
}
const result = target.apply(this, args);
cache.set(key, result);
return result;
};
}
/** Method to check if value is a non primitive. */View on GitHub (pinned to bb72145f9a)
Solutions
- Pass only JSON-serializable arguments (strings, numbers, booleans, plain objects/arrays) to memoized methods.
- Refactor to pass a stable primitive key (e.g. an id or path) instead of an object, and look up the object inside the method.
- Drop the `@memoize` decorator and implement an explicit cache keyed appropriately for complex arguments.
- Sanitize arguments before the call (strip circular refs/functions) if they are only used as keys.
Example fix
// before
@memoize loadUser(user: User) {...}
service.loadUser(someUserInstance); // throws
// after
@memoize loadUser(userId: string) {...}
service.loadUser(someUserInstance.id); Defensive patterns
Strategy: validation
Validate before calling
function isJsonSerializable(v: unknown): boolean {
try { JSON.stringify(v); return true; } catch { return false; }
}
if (!isJsonSerializable(arg)) throw new TypeError('Argument must be JSON-serializable for memoized methods'); Type guard
function isJsonSerializableArg(v: unknown): v is string | number | boolean | null | JsonValue {
try { JSON.stringify(v); return true; } catch { return false; }
} Try / catch
try {
memoizedService.load(complexObject);
} catch (e) {
if (e instanceof Error && e.message.includes('is JSON serializable')) {
// retry with a primitive key instead
memoizedService.load(complexObject.id);
} else { throw e; }
} Prevention
- Pass primitives (ids, paths) to memoized methods, not object instances.
- Avoid functions, Symbols, undefined, and circular structures as arguments.
- Remember the cache key is JSON.stringify(args) — keep args small and stable.
- Remove @memoize and use an explicit cache if arguments are inherently non-serializable.
When it happens
Trigger: Calling a `@memoize`-decorated method/getter with arguments that fail `isJSONSerializable` — objects with circular references, class instances with functions/Symbols, `undefined`, functions, DOM nodes, Buffers, etc.
Common situations: Passing `this`-bound objects, HttpParams/Request objects, or class instances as arguments to memoized methods; passing `undefined` or callback functions; memoizing methods that take complex runtime objects instead of primitive IDs.
Related errors
- Memoize decorator can only be used on methods or get accesso
- Cannot retrieve cache configuration as workspace is not defi
- Expected a JobHandler as second argument.
- Expected an object options as second argument.
- Expected name to be a string.
AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30).
Data as JSON: /api/errors/bd278b22d7e1b953.
Report an issue: GitHub.