JavaScript heap out of memory after upgrading to 4.3 #44299
Comments
Almost (young object promotion failed Allocation failed) exact same issue. obviously must be something specific about our codebase, but verbose outputs nothing so I dont know where we go from here. Perhaps providing some kind of dump might be useful for someone? Worth noting it happens after a very long time hanging.
|
We're experiencing this against both our front and backend applications which is interesting as they share little code. By any chance is anyone else here using Zod? It's perhaps the most type-complex library which we're using in both. |
@brudil Im using Zod too! |
@brudil I am also using Zod! |
Interesting, using Zod here as well, 3.1.0 and I can't |
I setup a minimal test case like so: import zod from 'zod'
export const SchemaExample = zod.object({
name: zod.string().min(1),
description: zod.string().min(1),
})
export type SchemaExampleType = zod.infer<typeof SchemaExample> Interestingly, in the simple case, this causes "maximum depth" TS errors rather than a hang. Here are the errors:
|
FWIW I'm not using Zod, but the codebase is quite large. |
Interesting. Perhaps its more t do with anything that uses recursive types. |
zod is incompatible with Typescript 4.3.x due a change in 4.3 for evaluating deep complex types. Since we do not use any 4.3 features (yet), lock typescript package to 4.2 until this is fixed see microsoft/TypeScript#43249, colinhacks/zod#443, colinhacks/zod#473, microsoft/TypeScript#44299
zod is incompatible with Typescript 4.3.x due a change in 4.3 for evaluating deep complex types. Since we do not use any 4.3 features (yet), lock typescript package to 4.2 until this is fixed see microsoft/TypeScript#43249, colinhacks/zod#443, colinhacks/zod#473, microsoft/TypeScript#44299
I'm going to investigate Zod, since there's a repro. Hopefully, the underlying issue will turn out to be the same as @dagstuan's. |
Introduced in #30639 (cc @weswigham). On the bright side, in that exact commit, the toy repro runs out of memory, so we've made improvements since then. |
Yeah, when we merged that we started exploring more types during relationship checking to test for compatibility which, for generatively expanding types, means manufacturing more types (before we hit somewhat arbitrary limiters) - in the intervening time, we've tightened up on some of those limiters/identities a bit, and that's generally how I've been going about "fixing" it - identify costly structures to compare, figure out how they're dodging our complexity limiters, and the update the complexity limiters to capture them. |
I'm getting similar error, and I have a (maybe) simpler repro: import { object, string } from "zod";
const validator = object({
_key: string()
}); That's enough to trigger the excessive stack depth error. My guess is that it has something to do with generic inference. |
Okay, it took a while, but here's a toy repro with no imports. export declare type ZodFormattedError<T> = T extends [any, ...any] ? {
[K in keyof T]?: ZodFormattedError<T[K]>;
} & {
_errors: string[];
} : T extends any[] ? ZodFormattedError<T[number]>[] & {
_errors: string[];
} : T extends object ? {
[K in keyof T]?: ZodFormattedError<T[K]>;
} & {
_errors: string[];
} : {
_errors: string[];
};
export declare class ZodError<T> {
format: () => ZodFormattedError<T>;
}
declare const c1: ZodError<number>;
const c2: ZodError<string> = c1; Personally, I find it easier to read like this: type ZodFormattedError<T> = T extends [any, ...any]
? { [K in keyof T]?: ZodFormattedError<T[K]>; } & { _errors: string[]; }
: T extends any[]
? ZodFormattedError<T[number]>[] & { _errors: string[]; }
: T extends object
? { [K in keyof T]?: ZodFormattedError<T[K]>; } & { _errors: string[]; }
: { _errors: string[]; };
interface ZodError<T> {
format: () => ZodFormattedError<T>;
}
declare const c1: ZodError<number>;
const c2: ZodError<string> = c1; |
Ooh, if you comment out these lines, it OOMs: type ZodFormattedError<T> = T extends [any, ...any]
? { [K in keyof T]?: ZodFormattedError<T[K]>; } & { _errors: string[]; }
: T extends any[]
? ZodFormattedError<T[number]>[] & { _errors: string[]; }
// : T extends object
// ? { [K in keyof T]?: ZodFormattedError<T[K]>; } & { _errors: string[]; }
: { _errors: string[]; };
interface ZodError<T> {
format: () => ZodFormattedError<T>;
}
declare const c1: ZodError<number>;
const c2: ZodError<string> = c1; |
And pulling out the intersection with type ZodFormattedError<T> = { _errors: string[]; } & (T extends [any, ...any]
? { [K in keyof T]?: ZodFormattedError<T[K]>; }
: T extends any[]
? ZodFormattedError<T[number]>[]
: T extends object
? { [K in keyof T]?: ZodFormattedError<T[K]>; }
: {}); (I think I got that right.) |
@weswigham Is there something smart we can do with the depth limit in the the toy repros? And does my mitigation look correct enough to submit as a PR to zod? |
is this a zod problem or a ts problem? I feel like this might be more of a ts problem, because something changed in ts 4.3 that broke zod |
@autumnblazey It's a TS problem, but a zod PR might help people until a new version of TS is released. Also, the proposed change to zod will likely make it faster even after the TS fix. |
@dagstuan Do you want to try running https://www.npmjs.com/package/@amcasey/ts-analyze-trace? It might identify a portion of your code (or imported package) that seems to trigger the problem and which you can share without divulging any IP. |
I run into the same issue with https://github.com/unional/type-plus. |
Bug Report
Memory
After upgrading to 4.3.2 I get a "JavaScript heap out of memory" exception when i try to run
tsc
. Downgrading to 4.2.4 does not yield the same error.It crashed.
No crash
The text was updated successfully, but these errors were encountered: