TypeScript: FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory

TypeScript Version: 2.2.1

ts-loader version: 1.3.2 and 2.0.1 (probably no matter) node version: v4.7.2 and v6.9.5 (probably no matter)

I use webpack + ts-loader with next config:

ts: {
	transpileOnly: true,
	compilerOptions: {
		target: 'ES5',
		jsx: 'react',
		sourceMap: true
	}
},

After upgrade typescript from 2.0.3 to 2.2.1 compilation fail with next error:

ts-loader: Using typescript@2.2.1 and /mnt/ssd/home/oleg/IdeaProjects/hc/application/src/tsconfig.json                                                                                           49% 1306/2000 build modules
<--- Last few GCs --->

  173682 ms: Mark-sweep 1354.8 (1435.6) -> 1354.8 (1435.6) MB, 979.1 / 0.0 ms [allocation failure] [GC in old space requested].
  174623 ms: Mark-sweep 1354.8 (1435.6) -> 1354.8 (1435.6) MB, 940.7 / 0.0 ms [allocation failure] [GC in old space requested].
  175574 ms: Mark-sweep 1354.8 (1435.6) -> 1357.5 (1407.6) MB, 951.1 / 0.0 ms [last resort gc].
  176520 ms: Mark-sweep 1357.5 (1407.6) -> 1360.5 (1407.6) MB, 945.5 / 0.0 ms [last resort gc].


<--- JS stacktrace --->

==== JS stack trace =========================================

Security context: 0x17e3fb1cfb51 <JS Object>
    1: toString [native v8natives.js:~642] [pc=0x331e2359bef6] (this=0x2fae35ff1a9 <Number: nan>,u=0x17e3fb104381 <undefined>)
    2: arguments adaptor frame: 0->1
    3: isNumericLiteralName [/mnt/ssd/home/oleg/IdeaProjects/hc/node_modules/typescript/lib/typescript.js:~35538] [pc=0x331e212c2339] (this=0x17e3fb1e6111 <JS Global Object>,name=0x1b5b1edec079 <String[8]: sendStat>)
    4: isNumeric...

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
 1: node::Abort() [grunt]
 2: 0x1096a4c [grunt]
 3: v8::Utils::ReportApiFailure(char const*, char const*) [grunt]
 4: v8::internal::V8::FatalProcessOutOfMemory(char const*, bool) [grunt]
 5: v8::internal::Factory::NewRawOneByteString(int, v8::internal::PretenureFlag) [grunt]
 6: v8::internal::Factory::NewStringFromOneByte(v8::internal::Vector<unsigned char const>, v8::internal::PretenureFlag) [grunt]
 7: v8::internal::Factory::NumberToString(v8::internal::Handle<v8::internal::Object>, bool) [grunt]
 8: v8::internal::Runtime_NumberToStringSkipCache(int, v8::internal::Object**, v8::internal::Isolate*) [grunt]
 9: 0x331e200092a7

Expected behavior: Compilation success

Actual behavior: Compilation fail

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 3
  • Comments: 47 (17 by maintainers)

Commits related to this issue

Most upvoted comments

[Summary for those who find this issue via Google.] [Edit: More detailed workaround-debugging instructions] [Edit: I wrote a more detailed guide.]

Previous bugs like this have all been caused by trying to compile large Javascript libraries in node_modules when allowJs: true. Typescript shouldn’t run out of memory on these libraries, but sometimes it does, particularly as we add more advanced analysis of like flow control. These analyses often work on unannotated code, which of course means that large Javascript libraries stress them the most.

While you’re waiting for us to fix these bugs, here’s how to find a workaround:

  1. Do you have "allowJs": true? Turn it off. Does compilation complete? There may be lots of errors, but if there is no crash, then the culprit is the compiler getting stuck on Javascript code.
    1. Install typings for libraries you use. The compiler will stop looking as soon as it sees the .d.ts and won’t even try to process .js or .ts files.
    2. Specifically "exclude" node_modules or "include" your source directory. This will help the compiler to know that it doesn’t need to process every library you depend on.
  2. Do you have "noImplicitAny": true? Turn it off. If compilation completes, then advanced analysis is the culprit.
    • Try adding more type annotations inside function bodies (especially large functions) before turning noImplicitAny back on. This will let the compiler skip some of its advanced inference. The oo-memory bugs I’ve seen in the last year have all been triggered by inference (either from control flow or for type arguments).

Finally, if you can share your project with us, it raises the probability we can fix the bug. A miniature repro is even better, of course, but that is difficult with crash bugs.

I’m still tracking down the cause of this bug, but I discovered that the repro problem is the same as #12735, which also used webpack. transpileOnly: true doesn’t initialize the typescript compiler correctly, such that the Array type doesn’t get included, which means that in let slides: any[] = [], : any[] is ignored.

That means the compiler tries to use its expanding array type inference. That’s where the exponential bug is, just like in #12735.

Workaround

In webpack.config.js, set transpileOnly: false. This correctly initialises the compiler.

To repro without webpack

use this tsconfig:

{
    "compilerOptions": {
        "experimentalDecorators": true,
        "baseUrl": "./",
        "target": "ES6",
        "noImplicitAny": true
    },
    "files": [
        "index.ts"
    ]
}

Remove the type annotation from the declaration of slides:

let slides = [];

As the figure above shows, you can control the exponential behaviour by varying the number of assignments.

I was able to fix it by having include in my tsconfig.json

Strange, I did not need to do that before

no, its not a final solution. My team is also suffering from this issue and had to increase the max old space size several times now. This week we are upgrading to Webpack 4 and testing the performance. So far the results are very promising.

Also, do you depend on fp-ts, fantasyland or monet? Those libraries are known to have problems running out of memory. (See #16029 or #16777)

Well, the bug occurs when webpack incorrectly initialises the compiler such that (1) the Array type is missing and (2) noImplicitAny: true; then it tries to compile a program that (3) has multiple assignments to (4) a variable initialised with an empty array. This leads to the following workarounds:

  1. Make sure the Array type is present via transpileOnly: false or by fixing webpack (ts-loader?) so that transpileOnly: true uses the compiler correctly.
  2. Set noImplicitAny: false in the webpack config. But this didn’t work for me, so it probably interferes with transpileOnly: true.
  3. Use only a single assignment, probably changing the structure to something like
let slides = {
  [SlideName.FIRST_LOGIN_WELCOME]: 'Let us show you around!',
  // ...
}
  1. Initialise slides to something besides an empty array, then overwrite the first entry:
let slides = [{ caption: 'Work around Typescript bug' }]

Since (1) doesn’t work for you, I’d probably recommend (4) since it’s the most obvious and can be removed once you get a version with the bug fixed.

I have not reproduced it. But I think it happens if you have other package.json root’s in one of a subfolder (maybe cause some conflicts with those packages etc.?). I have not specified include or files first because I was not so familiar how to configure tsconfig for the webpack loader - I thought you must not specify the files/include config because I don’t want to use typescript as builder quasi - but as default it just scans every sub folder no matter how complex/nested project structure you have. I think this breaks the neck of our poor guy.

However I think this shouldn’t end in a fatal error. More informative information were better.