Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash with Error: Content and Map of this Source is not available (only size() is supported) #14840

Closed
andreialecu opened this issue Nov 26, 2021 · 36 comments

Comments

@andreialecu
Copy link

Bug report

I'm running into Error: Content and Map of this Source is not available (only size() is supported) with Angular.

This seems to have been reported in various other places recently:
https://stackoverflow.com/questions/70066980/angular-12-content-and-map-of-this-source-is-not-available-only-size-is-suppo

What is the current behavior?

.../node_modules/webpack-sources/lib/SizeOnlySource.js:16
                return new Error(
                       ^

Error: Content and Map of this Source is not available (only size() is supported)
    at SizeOnlySource._error (.../node_modules/webpack-sources/lib/SizeOnlySource.js:16:10)
    at SizeOnlySource.buffer (.../node_modules/webpack-sources/lib/SizeOnlySource.js:30:14)
    at _isSourceEqual (.../node_modules/webpack/lib/util/source.js:21:51)
    at isSourceEqual (.../node_modules/webpack/lib/util/source.js:43:17)
    at Compilation.emitAsset (.../node_modules/webpack/lib/Compilation.js:4155:9)
    at .../node_modules/webpack/lib/Compiler.js:546:28
    at .../node_modules/webpack/lib/Compiler.js:1127:17
    at eval (eval at create (.../node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:13:1)
The terminal process "zsh '-c', 'yarn run start'" terminated with exit code: 1.

If the current behavior is a bug, please provide the steps to reproduce.

I don't have a clear reproduction, however I was able to add some logs in emitAsset here, which is part of the stack trace:

webpack/lib/Compilation.js

Lines 4171 to 4176 in 14582fc

if (!isSourceEqual(this.assets[file], source)) {
this.errors.push(
new WebpackError(
`Conflict: Multiple assets emit different content to the same filename ${file}`
)
);

I added:

	emitAsset(file, source, assetInfo = {}) {
		if (this.assets[file]) {
			try {
				!isSourceEqual(this.assets[file], source);
			} catch (err) {
				console.error(file, this.assets[file], source);
				throw err;
			}

The output before the crash is:

fontawesome-webfont.eot SizeOnlySource { _size: 165742 } RawSource {
  _valueIsBuffer: true,
  _value: <Buffer 6e 87 02 00 ac 86 02 00 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 90 01 00 00 00 00 4c 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 165692 more bytes>,
  _valueAsBuffer: <Buffer 6e 87 02 00 ac 86 02 00 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 90 01 00 00 00 00 4c 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 165692 more bytes>,
  _valueAsString: undefined
}

It always seems to crash on the same eot file. Notice that this.assets[file] for this file is a SizeOnlySource.

What is the expected behavior?

No crash.

Other relevant information:
webpack version: 5.60.0
Node.js version: 16.13.0
Operating System: MacOS 11.4
Additional tools: Angular 13.0.1

@alexander-akait
Copy link
Member

alexander-akait commented Nov 26, 2021

Expected, something try to get content there is not content, replaced after writing by webpack, please wait the answer of angular team, we can't fix it on our side, sorry

@andreialecu
Copy link
Author

Thanks, I opened angular/angular-cli#22237 as well.

@andreialecu
Copy link
Author

@alexander-akait after some discussion with an Angular team member in the issue mentioned above, it seems that they don't think this problem is on their side.

The stacktrace only mentions webpack from top to bottom, and I noticed that if I delete the webpack cache the problem goes away.

Would you mind taking a look at the discussion there? Thanks!

@alexander-akait
Copy link
Member

@andreialecu Can you create reproducible test repo?

@andreialecu
Copy link
Author

Unfortunately no, this is a huge project and it seems to be occurring very randomly as also noted in: angular/angular-cli#22237 (comment) where simply re-cloning got rid of the error.

The key part is probably figuring out why SizeOnlySource is being compared to a RawSource and how it ends up in that state. I'm hoping there's an easy way to simply audit the code based on that information.

@alexander-akait
Copy link
Member

alexander-akait commented Nov 27, 2021

I am afraid without more information, nobody can help with the problem, do you have enabled cache, can you try to disable, how often it happens? Is it watch/dev server/single build?

@andreialecu
Copy link
Author

Currently it's not happening in my project any more.

But it clears up after removing the cache. It also clears up randomly after messing with package.json dependencies.

However it also randomly comes back. I've had this come and go several times over the last few days.

Once it starts happening again I'll archive the project so I have a reproduction.

@alexander-akait
Copy link
Member

Thanks

@sokra
Copy link
Member

sokra commented Dec 2, 2021

This kind of error usually happens when trying to emit assets after the compiler has already written the assets to the output directory. (After writing webpack replaces the assets with SizeOnlySources, which drops the content for memory reasons)

From the stack trace it looks like a child compiler finishes very later and tries to emits its assets to the parent compiler.

So I think the problem is that somewhere a child compiler is started, but not correctly awaited for completion. That makes it timing dependent when the assets are emitted to the parent compiler, which could randomly cause this error.

@andreialecu
Copy link
Author

andreialecu commented Dec 2, 2021

@sokra from my observations I think your assumptions are correct.

When this was occurring, the process was as follows:

  • Angular starts an initial compilation. This takes a while and "Compilation successful" is printed.
  • Angular then automatically starts a second compilation which usually takes a second or so. Probably because everything is already cached. At this point it prints "Compilation successful" again. And then the error comes up a split second later. You can see this in my screenshot of the error.

I'm not sure what the reason for the double compilation is. Might be something internal to Angular.

@andreialecu
Copy link
Author

The screenshot I referred to is in this comment: angular/angular-cli#22237 (comment)

@alexander-akait
Copy link
Member

Angular then automatically starts a second compilation which usually takes a second or so

I think this shouldn't be happening, do you have custom plugins?

@alexander-akait
Copy link
Member

@andreialecu Anyway I strong recommend do not close angular/angular-cli#22237, I'm almost sure that the problem is on their side, no one except angular users faced with it (this is a pretty clear hint)

@sokra
Copy link
Member

sokra commented Dec 2, 2021

From the angular issue it sounds a bit like that might be related to css build. A font file could be referenced by css child compiler and main compiler. Is angular using mini-css?

@alan-agius4
Copy link

@sokra, yeah we are using mini-css.

@alexander-akait
Copy link
Member

Will be great to see more items in stack trace...

@andreialecu
Copy link
Author

@alexander-akait for some reason that's the entire stack trace (the part after ✔ Compiled successfully. is my own logging) :

✔ Compiled successfully.
fontawesome-webfont.eot SizeOnlySource { _size: 165742 } RawSource {
  _valueIsBuffer: true,
  _value: <Buffer 6e 87 02 00 ac 86 02 00 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 90 01 00 00 00 00 4c 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 165692 more bytes>,
  _valueAsBuffer: <Buffer 6e 87 02 00 ac 86 02 00 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 90 01 00 00 00 00 4c 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 165692 more bytes>,
  _valueAsString: undefined
}
.../node_modules/webpack-sources/lib/SizeOnlySource.js:16
                return new Error(
                       ^

Error: Content and Map of this Source is not available (only size() is supported)
    at SizeOnlySource._error (.../node_modules/webpack-sources/lib/SizeOnlySource.js:16:10)
    at SizeOnlySource.buffer (.../node_modules/webpack-sources/lib/SizeOnlySource.js:30:14)
    at _isSourceEqual (.../node_modules/webpack/lib/util/source.js:21:51)
    at isSourceEqual (.../node_modules/webpack/lib/util/source.js:43:17)
    at Compilation.emitAsset (.../node_modules/webpack/lib/Compilation.js:4156:6)
    at .../node_modules/webpack/lib/Compiler.js:546:28
    at .../node_modules/webpack/lib/Compiler.js:1127:17
    at eval (eval at create (.../node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:13:1)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
The terminal process "zsh '-c', 'yarn run start'" terminated with exit code: 1.

@andreialecu
Copy link
Author

I'm not sure if this is in any way helpful, but once it starts occurring it seems to always be the same file. The only place that file is referenced is through the font-awesome npm package:

https://unpkg.com/font-awesome@4.7.0/scss/_path.scss

Notice how it's listed twice, once with a query string. I took a look through webpack sources and I notice that there's some logic related to query strings:

webpack/lib/Compiler.js

Lines 592 to 604 in 122db57

const queryStringIdx = targetFile.indexOf("?");
if (queryStringIdx >= 0) {
targetFile = targetFile.substr(0, queryStringIdx);
// We may remove the hash, which is in the query string
// So we recheck if the file is immutable
// This doesn't cover all cases, but immutable is only a performance optimization anyway
immutable =
immutable &&
(includesHash(targetFile, info.contenthash) ||
includesHash(targetFile, info.chunkhash) ||
includesHash(targetFile, info.modulehash) ||
includesHash(targetFile, info.fullhash));
}

immutable seem to then be used to consider whether to turn an asset into a SizeOnlySource later below.

Running a full angular build (non watch-mode) works. It works so well actually that it seems to clear up the initial error so now I can no longer reproduce it, again. It does pop up randomly though, so I'm hoping next time I can troubleshoot it further.

@alexander-akait
Copy link
Member

Sounds like a cache problem... Do you enable cache?

@andreialecu
Copy link
Author

Yes, the cache is enabled, I mentioned it earlier:

The stacktrace only mentions webpack from top to bottom, and I noticed that if I delete the webpack cache the problem goes away.

@alexander-akait
Copy link
Member

Can you try to increase stack trace using --stack-trace-limit (https://nodejs.org/api/cli.html)?

@alan-agius4
Copy link

Following a convo on discord with @andreialecu, it turns out that this stylesheet is actually referenced in a component and therefore it doesn’t use mini-css. I therefore suspect that this might be an issue with our plugin.

@alan-agius4
Copy link

While digging into this, I stumbled upon the double incremental re-builds issue when the cache is restored. There appears to be an issue with Webpack, when loaders are not hoisted to the top level node_modules and during watch mode.

More info: #14911

@alexander-akait
Copy link
Member

@alan-agius4 hm, do you reinstall deps in watch mode?

@alan-agius4
Copy link

alan-agius4 commented Dec 6, 2021

No, see steps in #14911 (comment). Note, this is not related to the only size() is supported issue. Just wanted to mention it here, since some people mentioned the double rebuild problem here.

@alan-agius4
Copy link

alan-agius4 commented Dec 6, 2021

Regarding the original issue, what I think is happening is that we are storing the assets from child compilers in a Map.

for (const { info, name, source } of childCompilation.getAssets()) {
   this.assetCache.set(cacheKey, { info, name, source });
}

Later on during an incremental build, we are re-emitting these assets from cache.

for (const [, { name, source, info }] of this.assetCache) {
   this._parentCompilation.emitAsset(name, source, info);
}

I suspect that in some cases, the source is mutated to SizeOnlySources. My 2 cents would be that in the cache we store source as string or buffer instead of the source Instance.

Ie:

this.assetCache.set(cacheKey, { info, name, source: source.source() });

And when we re-emit, we create a new RawSource everytime.

this._parentCompilation.emitAsset(name, new sources.RawSource(source), info);

@alexander-akait
Copy link
Member

hm, I think you should not store string or buffer, only sources have cache logic, so better to store them and avoid creating sources.RawSource, because it is also bad for performance

@alan-agius4
Copy link

Actually, I was wrong, at first seeing the logic here, the asset is not mutated since we are creating a new object each time, so back to square one.

@alexander-akait
Copy link
Member

Logic for child compilations is the same as for common compilations, and yes source can be SizeOnlySource if child compilation is cacheable, you can mark modules are not cachable to avoid this problem, but better to store source instead string or buffer, also it will be faster, maybe if you provide example of code I can help

@alan-agius4
Copy link

Had a chat with @alexander-akait, which firstly I'd like to thank.

Unfortunately, we didn't find anything suspicions that could cause this issue and hence without a reproduction it would be hard to get to the bottom of this.

@alexander-akait also suggested that you can add a breakpoint/console.log here https://github.com/webpack/webpack-sources/blob/main/lib/SizeOnlySource.js#L15 and https://github.com/webpack/webpack/blob/main/lib/Compiler.js#L546.

@andreialecu
Copy link
Author

andreialecu commented Dec 8, 2021

Can you try to increase stack trace using --stack-trace-limit (nodejs.org/api/cli.html)?

I keep getting this error on and off, and I tried adding Error.stackTraceLimit = Infinity; and longjohn. I'm not sure if either are supposed to work any more, but they didn't change anything.

I'm on Node 16.13.0, and this is an async unhandled promise error, which quits the process. There's a similar stack trace shown here: nodejs/node#11865 (comment)

I'm not sure why I can't get a longer stack trace.

In the mean time I've been trying to debug it further and I noticed that the double compilation issue in my case is caused by a missing/leftover file in angular.json's assets field.

It appears that a recompilation is triggered with changedFiles just containing the path to that missing file. This is possibly an Angular issue. Not sure if #14911 (comment) is related or not. @alan-agius4 might be able to clarify (I also left additional details on Discord)

Other findings are that if I try to copy the entire project somewhere else, the error will not occur. I even tried to use rsync to preserve file access times, without success. After inspecting the Angular cache files, it appears that full FS paths are hard-coded/baked into the cache. This may trigger an invalidation when the compilation is being ran from elsewhere, and it clears the error.

I've also been trying to add or remove various things to angular's webpack plugin without success. Once the error happens it keeps happening until the cache is invalidated.

@andreialecu
Copy link
Author

To add to the above, I thought the error was triggered by the second compilation because it would only ever occur after it - however after removing the leftover file it now compiles just once.

The error still occurs, it just happens a second or so after ✔ Compiled successfully. is printed by Angular.

Here's a recording. (there are some weird console.logs showing as well, from my debugging)

Screen.Recording.2021-12-08.at.11.31.20.mov

@alan-agius4
Copy link

@andreialecu, is it a possibility to either share your project (privately) or schedule a call so that we can debug this together?

@andreialecu
Copy link
Author

@alan-agius4 yes, sure. Let's schedule a time via Discord.

@alan-agius4
Copy link

FYI @alexander-akait angular/angular-cli#22237 (comment)

@DineshCodeFlow
Copy link

Run:
rm -rf .angular and then ng serve

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants