{"record":{"id":"c17f6e2b39dd3aac","repo":"n8n-io/n8n","slug":"filesystem-this-id-is-not-ready-status-th","errorCode":null,"errorMessage":"Filesystem \"${this.id}\" is not ready (status: ${this.status})","messagePattern":"Filesystem \"(.+?)\" is not ready \\(status: (.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/@n8n/agents/src/workspace/filesystem/base-filesystem.ts","lineNumber":92,"sourceCode":"\t\t\t\t// Non-fatal: bad callback shouldn't kill a healthy filesystem\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthis.status = 'error';\n\t\t\tthis.error = error instanceof Error ? error.message : String(error);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync init(): Promise<void> {\n\t\t// Default no-op — subclasses override\n\t}\n\n\tprotected async ensureReady(): Promise<void> {\n\t\tif (this.status !== 'ready') {\n\t\t\tawait this._init();\n\t\t}\n\t\tif (this.status !== 'ready') {\n\t\t\tthrow new Error(`Filesystem \"${this.id}\" is not ready (status: ${this.status})`);\n\t\t}\n\t}\n\n\tasync _destroy(): Promise<void> {\n\t\tif (this.status === 'destroyed') return;\n\n\t\tif (this.status === 'pending') {\n\t\t\tthis.status = 'destroyed';\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.destroyPromise) return await this.destroyPromise;\n\n\t\tthis.destroyPromise = this.executeDestroy();\n\t\ttry {\n\t\t\tawait this.destroyPromise;\n\t\t} finally {\n\t\t\tthis.destroyPromise = undefined;","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/agents/src/workspace/filesystem/base-filesystem.ts#L74-L110","documentation":"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.","triggerScenarios":"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'.","commonSituations":"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.","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."],"exampleFix":"// before (subclass bug)\nasync _init() {\n  await this.client.connect();\n  // forgot to set status\n}\n\n// after\nasync _init() {\n  await this.client.connect();\n  this.status = 'ready';\n}","handlingStrategy":"validation","validationCode":"function isReady(fs: { status: string }): boolean {\n  return fs.status === 'ready';\n}\n// before a heavy op:\nif (!isReady(filesystem)) {\n  await filesystem.init?.();\n}\nif (!isReady(filesystem)) throw new Error('filesystem not ready — recreate workspace');","typeGuard":null,"tryCatchPattern":"try {\n  await filesystem.readFile(path);\n} catch (e) {\n  if (e instanceof Error && /is not ready/.test(e.message)) {\n    // terminal-ish: recreate sandbox + filesystem, then retry once\n  } else throw e;\n}","preventionTips":["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."],"tags":["filesystem","lifecycle","state-machine","agents"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}