{"record":{"id":"bfd1c0cef7d64606","repo":"n8n-io/n8n","slug":"file-input-path-is-not-loaded","errorCode":null,"errorMessage":"File \"${input.path}\" is not loaded.","messagePattern":"File \"(.+?)\" is not loaded\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/@n8n/agents/src/workspace/tools/batch-str-replace-file.ts","lineNumber":75,"sourceCode":"\t\t)\n\t\t.input(inputSchema)\n\t\t.output(outputSchema)\n\t\t.handler(async (input, ctx) => {\n\t\t\ttry {\n\t\t\t\tconst content = await filesystem.readFile(input.path, {\n\t\t\t\t\tencoding: 'utf-8',\n\t\t\t\t\tabortSignal: ctx.abortSignal,\n\t\t\t\t});\n\t\t\t\tconst editor = new TextEditorDocument({ initialText: content.toString() });\n\t\t\t\tconst result = editor.executeBatch(input.replacements);\n\n\t\t\t\tif (isBatchReplaceResult(result)) {\n\t\t\t\t\treturn { success: false, error: 'Batch replacement failed.', results: result };\n\t\t\t\t}\n\n\t\t\t\tconst editedContent = editor.getText();\n\t\t\t\tif (editedContent === null) {\n\t\t\t\t\tthrow new Error(`File \"${input.path}\" is not loaded.`);\n\t\t\t\t}\n\n\t\t\t\tawait filesystem.writeFile(input.path, editedContent, {\n\t\t\t\t\toverwrite: true,\n\t\t\t\t\tabortSignal: ctx.abortSignal,\n\t\t\t\t});\n\t\t\t\treturn { success: true, result };\n\t\t\t} catch (error) {\n\t\t\t\tif (isAbortError(error)) throw error;\n\t\t\t\treturn createErrorOutput(error);\n\t\t\t}\n\t\t})\n\t\t.build();\n}\n","sourceCodeStart":57,"sourceCodeEnd":90,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/agents/src/workspace/tools/batch-str-replace-file.ts#L57-L90","documentation":"In the batch-str-replace-file tool, after readFile populates a TextEditorDocument and executeBatch runs, getText() should return the edited string. If it returns null, the document has no loaded text — an internal invariant of TextEditorDocument that should not be reachable given initialText was just set from the file content. The throw is a defensive guard against a regression that would otherwise write `null` to the file.","triggerScenarios":"Effectively unreachable in normal flow (initialText is set from content right before). Would fire only if TextEditorDocument's internal text state was cleared by executeBatch (e.g. a future refactor resets the buffer) or if a subclass overrode behavior to null the document.","commonSituations":"A bug/regression in TextEditorDocument where executeBatch mutates state such that getText() returns null; concurrent reuse of the same editor instance; future code change that clears initialText.","solutions":["Treat this as an internal bug — file an issue against @n8n/agents with the input path and replacements.","Retry the operation on a fresh TextEditorDocument instance.","As a workaround, use the single str_replace tool instead of the batch variant."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  return await batchStrReplace(...);\n} catch (e) {\n  if (e instanceof Error && /is not loaded/.test(e.message)) {\n    // internal invariant — retry on a fresh editor, or fall back to single str_replace\n  } else throw e;\n}","preventionTips":["Treat 'is not loaded' as an internal bug — report it with the input path + replacements.","Don't reuse a TextEditorDocument across files.","Prefer the single str_replace tool if the batch variant misbehaves."],"tags":["tools","text-editor","invariant","agents"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}