{"record":{"id":"a2aa67b8e5a87203","repo":"Mintplex-Labs/anything-llm","slug":"cannot-copy-symbolic-link-source-symlinks-are","errorCode":null,"errorMessage":"Cannot copy symbolic link: ${source}. Symlinks are not allowed during copy operations.","messagePattern":"Cannot copy symbolic link: (.+?)\\. Symlinks are not allowed during copy operations\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"server/utils/agents/aibitat/plugins/filesystem/copy-file.js","lineNumber":9,"sourceCode":"const fs = require(\"fs/promises\");\nconst path = require(\"path\");\nconst filesystem = require(\"./lib.js\");\n\nasync function copyRecursive(source, destination) {\n  const lstat = await fs.lstat(source);\n\n  if (lstat.isSymbolicLink()) {\n    throw new Error(\n      `Cannot copy symbolic link: ${source}. Symlinks are not allowed during copy operations.`\n    );\n  }\n\n  if (lstat.isDirectory()) {\n    await fs.mkdir(destination, { recursive: true });\n    const entries = await fs.readdir(source);\n    for (const entry of entries) {\n      await copyRecursive(\n        path.join(source, entry),\n        path.join(destination, entry)\n      );\n    }\n  } else {\n    await fs.copyFile(source, destination);\n  }\n}\n","sourceCodeStart":1,"sourceCodeEnd":27,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/526360e320da9d1b36074be5ed64fe76e5bbfbbd/server/utils/agents/aibitat/plugins/filesystem/copy-file.js#L1-L27","documentation":"Thrown by copyRecursive() in the filesystem copy-file plugin when fs.lstat() reports the source is a symbolic link. The tool deliberately refuses to traverse or copy symlinks as a security measure to prevent following links outside the allowed workspace. Because copyRecursive recurses into directories, a symlink nested anywhere inside a copied directory also triggers this.","triggerScenarios":"Calling the filesystem-copy-file tool where the source path, or any entry within a source directory, is a symbolic link. The error fires before any copy attempt for that entry. The handler catches it and returns the message as a string result to the agent rather than throwing to the caller.","commonSituations":"User workspace contains symlinks (e.g., linked node_modules, config shortcuts); copying a directory tree that includes linked files; an agent attempting to back up a folder with shortcuts.","solutions":["Resolve the symlink to its real target before copying, then copy the resolved path (which itself must be within allowed directories).","Exclude symlinked entries from the copy operation.","Replace symlinks with real files if they must be copied.","Copy individual real files rather than a directory containing symlinks."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const fs = require(\"fs/promises\");\nasync function assertNotSymlink(p) {\n  const st = await fs.lstat(p);\n  if (st.isSymbolicLink())\n    throw new Error(`Refusing to copy symlink ${p}; resolve it first`);\n}","typeGuard":null,"tryCatchPattern":"// the tool handler already catches this and returns a string result;\n// in custom callers, catch and resolve the link target instead\ntry { await copyRecursive(src, dst); }\ncatch (e) { if (e.message.includes(\"symbolic link\")) { /* resolve real path */ } else throw e; }","preventionTips":["Resolve symlinks to their real targets before copying.","Audit workspace directories for symlinks before bulk copy operations.","Prefer copying real files rather than directories that may contain links."],"tags":["filesystem","security","symlink","copy"],"backgroundTag":null,"analyzedSha":"526360e320da9d1b36074be5ed64fe76e5bbfbbd","analyzedAt":"2026-08-13T01:45:47.170Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}