Summary
On Windows, OSLS packaging can fail with the following error:
Cannot read file .babelrc due to: file changed between metadata collection and stream open
After investigating, this appears to be a false positive in the streaming zip safety check.
The file is not actually changing. The failure seems to be caused by different dev values returned by fs.stat(path) and fileHandle.stat() for the same unchanged file.
Environment
- OS: Windows
- Shell: PowerShell
- Node runtime: Node.js 24.x
- OSLS version where the issue occurs:
3.73.0
- Project package dependency:
Because the dependency range is loose, a fresh install resolved OSLS to 3.73.0.
Error
During deploy/package, packaging fails with:
Cannot read file .babelrc due to: file changed between metadata collection and stream open
The referenced file is tiny and stable:
{
"presets": [
"@babel/preset-env",
"@babel/preset-typescript"
]
}
Investigation
The error appears to come from:
lib/plugins/package/lib/zip-service.js
Specifically:
const assertSameFile = (entry, currentStat) => {
const sameIdentity =
entry.stat.dev === currentStat.dev &&
entry.stat.ino === currentStat.ino;
const sameContentMetadata =
entry.stat.size === currentStat.size &&
entry.stat.mtimeMs === currentStat.mtimeMs;
if (!sameIdentity || !sameContentMetadata) {
throw new Error('file changed between metadata collection and stream open');
}
};
I reproduced the metadata mismatch directly with Node:
const fs = require('fs/promises');
(async () => {
const p = '.babelrc';
const a = await fs.stat(p);
const h = await fs.open(p, 'r');
const b = await h.stat();
await h.close();
console.log(JSON.stringify({
path: {
dev: a.dev,
ino: a.ino,
size: a.size,
mtimeMs: a.mtimeMs,
},
handle: {
dev: b.dev,
ino: b.ino,
size: b.size,
mtimeMs: b.mtimeMs,
},
same:
a.dev === b.dev &&
a.ino === b.ino &&
a.size === b.size &&
a.mtimeMs === b.mtimeMs,
}, null, 2));
})();
Output:
{
"path": {
"dev": 0,
"ino": 562949955664956,
"size": 83,
"mtimeMs": 1780191134753.168
},
"handle": {
"dev": 1587983220,
"ino": 562949955664956,
"size": 83,
"mtimeMs": 1780191134753.168
},
"same": false
}
The file identity/content metadata is otherwise stable:
ino matches
size matches
mtimeMs matches
- only
dev differs
So the file was not modified between metadata collection and stream open.
Why this looks related to recent packaging changes
The relevant behavior appears to have been introduced around the streaming zip packaging work.
The v3.68.0 release notes include:
Stream zip packaging and artifact hashing to fix OOM
The v3.69.0 release notes include a related follow-up:
Close zip stream file handle on simulated failure
Release notes:
The streaming zip implementation makes sense, but the equality check appears to be too strict for Windows/Node filesystem metadata.
Expected Behavior
Packaging should not fail when the file has not actually changed.
If only dev differs between fs.stat(path) and fileHandle.stat() on Windows, OSLS should not report the file as changed.
Actual Behavior
Packaging fails with:
Cannot read file .babelrc due to: file changed between metadata collection and stream open
Suggested Fix
Possible approaches:
- Do not compare
stat.dev on Windows.
- Compare only reliable content metadata for this safety check, such as:
- Treat
dev mismatch as non-fatal when process.platform === 'win32'.
For example:
const sameIdentity =
process.platform === 'win32'
? entry.stat.ino === currentStat.ino
: entry.stat.dev === currentStat.dev &&
entry.stat.ino === currentStat.ino;
Or, more conservatively, only use dev when both values are non-zero and equal semantics are known to be reliable.
const sameDevice =
entry.stat.dev === 0 ||
currentStat.dev === 0 ||
entry.stat.dev === currentStat.dev;
const sameIdentity =
sameDevice &&
entry.stat.ino === currentStat.ino;
Workaround
Pinning OSLS to an older version that does not fail during packaging avoids the issue.
However, this is not ideal because projects using a semver range like:
can resolve to newer versions and start failing unexpectedly on Windows.
Disclosure
This issue was drafted with AI assistance, based on my own investigation, reproduction steps, and observed results.
Summary
On Windows, OSLS packaging can fail with the following error:
After investigating, this appears to be a false positive in the streaming zip safety check.
The file is not actually changing. The failure seems to be caused by different
devvalues returned byfs.stat(path)andfileHandle.stat()for the same unchanged file.Environment
3.73.0{ "osls": "^3.61.1" }Because the dependency range is loose, a fresh install resolved OSLS to
3.73.0.Error
During deploy/package, packaging fails with:
The referenced file is tiny and stable:
{ "presets": [ "@babel/preset-env", "@babel/preset-typescript" ] }Investigation
The error appears to come from:
Specifically:
I reproduced the metadata mismatch directly with Node:
Output:
{ "path": { "dev": 0, "ino": 562949955664956, "size": 83, "mtimeMs": 1780191134753.168 }, "handle": { "dev": 1587983220, "ino": 562949955664956, "size": 83, "mtimeMs": 1780191134753.168 }, "same": false }The file identity/content metadata is otherwise stable:
inomatchessizematchesmtimeMsmatchesdevdiffersSo the file was not modified between metadata collection and stream open.
Why this looks related to recent packaging changes
The relevant behavior appears to have been introduced around the streaming zip packaging work.
The
v3.68.0release notes include:The
v3.69.0release notes include a related follow-up:Release notes:
The streaming zip implementation makes sense, but the equality check appears to be too strict for Windows/Node filesystem metadata.
Expected Behavior
Packaging should not fail when the file has not actually changed.
If only
devdiffers betweenfs.stat(path)andfileHandle.stat()on Windows, OSLS should not report the file as changed.Actual Behavior
Packaging fails with:
Suggested Fix
Possible approaches:
stat.devon Windows.inosizemtimeMsdevmismatch as non-fatal whenprocess.platform === 'win32'.For example:
Or, more conservatively, only use
devwhen both values are non-zero and equal semantics are known to be reliable.Workaround
Pinning OSLS to an older version that does not fail during packaging avoids the issue.
However, this is not ideal because projects using a semver range like:
{ "osls": "^3.61.1" }can resolve to newer versions and start failing unexpectedly on Windows.
Disclosure
This issue was drafted with AI assistance, based on my own investigation, reproduction steps, and observed results.