n8n-io/n8n · error
Filesystem "${this.id}" is not ready (status: ${this.status}
Error message
Filesystem "${this.id}" is not ready (status: ${this.status}) What it means
BaseFilesystem.ensureReady() is the gate every filesystem operation passes through (via withFs). If status is not 'ready' it calls _init(); if status is STILL not 'ready' afterwards, the adapter is unusable and the call would hit an uninitialized backend, so it throws with the observed status rather than proceed silently. This is a lifecycle/state-machine invariant violation.
Source
Thrown at packages/@n8n/agents/src/workspace/filesystem/base-filesystem.ts:92
// Non-fatal: bad callback shouldn't kill a healthy filesystem
}
} catch (error) {
this.status = 'error';
this.error = error instanceof Error ? error.message : String(error);
throw error;
}
}
async init(): Promise<void> {
// Default no-op — subclasses override
}
protected async ensureReady(): Promise<void> {
if (this.status !== 'ready') {
await this._init();
}
if (this.status !== 'ready') {
throw new Error(`Filesystem "${this.id}" is not ready (status: ${this.status})`);
}
}
async _destroy(): Promise<void> {
if (this.status === 'destroyed') return;
if (this.status === 'pending') {
this.status = 'destroyed';
return;
}
if (this.destroyPromise) return await this.destroyPromise;
this.destroyPromise = this.executeDestroy();
try {
await this.destroyPromise;
} finally {
this.destroyPromise = undefined;View on GitHub (pinned to 5ac6606e81)
Solutions
- Read the status in the error text: 'destroyed' means create a new workspace — the object is not recoverable; 'pending'/'error' usually means init failed, so inspect the underlying init error.
- Ensure any subclass _init() sets `this.status = 'ready'` on success and rethrows on failure (don't swallow).
- For transient provider failures, recreate the sandbox + filesystem and retry the op rather than reusing the object.
Example fix
// before (subclass bug)
async _init() {
await this.client.connect();
// forgot to set status
}
// after
async _init() {
await this.client.connect();
this.status = 'ready';
} Defensive patterns
Strategy: validation
Validate before calling
function isReady(fs: { status: string }): boolean {
return fs.status === 'ready';
}
// before a heavy op:
if (!isReady(filesystem)) {
await filesystem.init?.();
}
if (!isReady(filesystem)) throw new Error('filesystem not ready — recreate workspace'); Try / catch
try {
await filesystem.readFile(path);
} catch (e) {
if (e instanceof Error && /is not ready/.test(e.message)) {
// terminal-ish: recreate sandbox + filesystem, then retry once
} else throw e;
} Prevention
- In custom BaseFilesystem subclasses, always set status='ready' on successful _init and rethrow on failure.
- Don't reuse filesystem objects after destroy() — recreate the workspace.
- Log status transitions during init to catch silent no-ops.
When it happens
Trigger: Any filesystem op (readFile, writeFile, stat, list…) invoked when: a subclass _init() threw and left status as 'pending'/'error'; _init() returned without setting status='ready' (subclass bug); the filesystem was concurrently destroyed between the status check and the re-check; _destroy() ran and transitioned status to 'destroyed'.
Common situations: Daytona/E2B auth failed during init but the error was swallowed; the sandbox backing the filesystem was destroyed while an op was queued; a custom BaseFilesystem subclass overrides _init() and forgets `this.status = 'ready'` on success.
Related errors
- Sandbox "${this.name}" has been destroyed
- Sandbox "${this.name}" failed to start (status: ${this.statu
- File not found: ${path}
- Daytona sandbox "${this.id}" is not running
- ${toolName} requires resumeSubAgent and cancelSubAgent to be
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/c17f6e2b39dd3aac.
Report an issue: GitHub.