microsoft/TypeScript · error · Error
Cannot shadow a mutable file system.
Error message
Cannot shadow a mutable file system.
What it means
Thrown by FileSystem.shadow (vfsUtil.ts:162) when asked to shadow a file system that is not yet read-only. Shadowing shares data lazily between the original and the copy; allowing it on a mutable FS would let the original keep mutating state the shadow has already inherited. Callers must freeze the source first via makeReadonly().
Source
Thrown at src/harness/vfsUtil.ts:162
if (this.isReadonly) return;
const fs = new FileSystem(this.ignoreCase, { time: this._time });
fs._lazy = this._lazy;
fs._cwd = this._cwd;
fs._time = this._time;
fs._shadowRoot = this._shadowRoot;
fs._dirStack = this._dirStack;
fs.makeReadonly();
this._lazy = {};
this._shadowRoot = fs;
}
/**
* Gets a shadow copy of this file system. Changes to the shadow copy do not affect the
* original, allowing multiple copies of the same core file system without multiple copies
* of the same data.
*/
public shadow(ignoreCase: boolean = this.ignoreCase): FileSystem {
if (!this.isReadonly) throw new Error("Cannot shadow a mutable file system.");
if (ignoreCase && !this.ignoreCase) throw new Error("Cannot create a case-insensitive file system from a case-sensitive one.");
const fs = new FileSystem(ignoreCase, { time: this._time });
fs._shadowRoot = this;
fs._cwd = this._cwd;
return fs;
}
/**
* Gets or sets the timestamp (in milliseconds) used for file status, returning the previous timestamp.
*
* @link http://pubs.opengroup.org/onlinepubs/9699919799/functions/time.html
*/
public time(value?: number): number {
if (value !== undefined) {
if (this.isReadonly) throw createIOError("EPERM");
this._time = value;
}
else if (!this.isReadonly) {
View on GitHub (pinned to b465fdbfe1)
Solutions
- Call `fs.makeReadonly()` immediately before `fs.shadow()`.
- Prefer `fs.snapshot()` if you actually want to fork the current mutable state — snapshot internally freezes a clone and re-points _shadowRoot.
- Freeze the base VFS once in beforeAll/module init, then shadow per test.
- Audit setup helpers to guarantee makeReadonly is called before any shadow.
Example fix
// before const base = new VirtualFileSystem(/* ... */); populate(base); const fork = base.shadow(); // throws // after — freeze first const base = new VirtualFileSystem(/* ... */); populate(base); base.makeReadonly(); const fork = base.shadow();
Defensive patterns
Strategy: validation
Validate before calling
// Freeze before shadowing. if (!fs.isReadonly) fs.makeReadonly(); const fork = fs.shadow();
Type guard
function isReadOnlyFs(fs: FileSystem): boolean {
return fs.isReadonly === true;
} Prevention
- Always call makeReadonly before shadow.
- Build and freeze shared base VFSes once in beforeAll/module init.
- Prefer snapshot() when you want to fork mutable state.
When it happens
Trigger: Test code calls `fs.shadow()` on a freshly-built virtual FS that has not yet been frozen. The constructor leaves isReadonly false; shadowing requires the source to be immutable so the copy-on-write invariants hold.
Common situations: Building a shared base VFS once and forking shadows per test without freezing; refactoring setup code that previously called makeReadonly; copy-pasting shadow usage from a readonly fixture into a mutable one.
Related errors
- Cannot create a case-insensitive file system from a case-sen
- verifyCurrentLineContent\n
- verifyFileContent in file '${fileName}' failed:\n${showTextD
- Expected at least one js file to be emitted or at least one
- Variations in test option '@${varyBy}' resulted in an empty
AI-assisted analysis of microsoft/TypeScript@b465fdbfe1 (2026-08-12).
Data as JSON: /api/errors/cf53c13cf2963fba.
Report an issue: GitHub.