{"record":{"id":"b83b7cedf2d01f50","repo":"mastra-ai/mastra","slug":"experiment-worker-artifacts-cannot-contain-absolut","errorCode":null,"errorMessage":"Experiment worker artifacts cannot contain absolute symlinks: ${artifactPath}","messagePattern":"Experiment worker artifacts cannot contain absolute symlinks: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/commands/experiment/ExperimentBundler.ts","lineNumber":272,"sourceCode":"    for (const name of entries.sort((left, right) => (left < right ? -1 : left > right ? 1 : 0))) {\n      const fullPath = join(directory, name);\n      const artifactPath = relative(root, fullPath).replaceAll('\\\\', '/');\n      if (artifactPath === 'experiment-worker-manifest.json' || artifactPath === 'node_modules') continue;\n\n      const stats = await lstat(fullPath);\n      if (stats.isDirectory()) {\n        await visit(fullPath);\n      } else if (stats.isFile()) {\n        files.push({\n          path: artifactPath,\n          sha256: createHash('sha256')\n            .update(await readFile(fullPath))\n            .digest('hex'),\n        });\n      } else if (stats.isSymbolicLink()) {\n        const target = await readlink(fullPath);\n        if (isAbsolute(target)) {\n          throw new Error(`Experiment worker artifacts cannot contain absolute symlinks: ${artifactPath}`);\n        }\n        const resolvedTarget = resolve(dirname(fullPath), target);\n        const artifactTarget = relative(root, resolvedTarget);\n        if (artifactTarget === '..' || artifactTarget.startsWith(`..${sep}`) || isAbsolute(artifactTarget)) {\n          throw new Error(`Experiment worker artifacts cannot contain escaping symlinks: ${artifactPath}`);\n        }\n        files.push({\n          path: artifactPath,\n          type: 'symlink',\n          target,\n          sha256: createHash('sha256').update(target).digest('hex'),\n        });\n      } else {\n        throw new Error(`Unsupported artifact file type: ${artifactPath}`);\n      }\n    }\n  };\n  await visit(root);","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/cli/src/commands/experiment/ExperimentBundler.ts#L254-L290","documentation":"When digesting the built artifact to write the experiment worker manifest, any symbolic link whose target is an absolute path is rejected. Absolute symlinks would break portability (they point outside the artifact and depend on the build machine's layout) and can be a security risk when artifacts are unpacked elsewhere. The build fails fast with the offending artifact-relative path.","triggerScenarios":"collectFileDigests encounters a symlink inside the bundler output directory whose readlink() target begins with '/', e.g. a dependency or postinstall script that created an absolute symlink into node_modules or a system path.","commonSituations":"A package's postinstall creating absolute symlinks; pnpm/npm linking global binaries into the output; copying files with `cp -s /abs/path` into src so the absolute link ends up in the bundle; OS/package-manager-generated links in the output directory.","solutions":["Find the file listed in the message and remove or recreate the symlink as a relative symlink.","Replace absolute symlinks with real file copies in your source/package before building.","Check node_modules dependencies for postinstall scripts that create absolute links and pin/vendor a fixed version.","Rebuild into a clean output directory to rule out stale links from a previous build."],"exampleFix":"// before\nln -s /home/me/project/vendor/lib ./lib\n// after\nln -s ../vendor/lib ./lib   # relative target, stays inside the artifact","handlingStrategy":"validation","validationCode":"import { lstat, readlink, readdir } from 'node:fs/promises';\nimport { isAbsolute, join } from 'node:path';\nasync function assertNoAbsoluteSymlinks(dir: string) {\n  for (const e of await readdir(dir, { withFileTypes: true })) {\n    const p = join(dir, e.name);\n    if (e.isDirectory()) await assertNoAbsoluteSymlinks(p);\n    else if (e.isSymbolicLink() && isAbsolute(await readlink(p))) throw new Error(`absolute symlink: ${p}`);\n  }\n}","typeGuard":"null","tryCatchPattern":"try {\n  await buildExperimentWorker({ outputDir });\n} catch (e) {\n  if (String(e?.message).includes('absolute symlinks')) {\n    console.error('Replace the listed symlink with a relative link or a real copy');\n  } else throw e;\n}","preventionTips":["Use relative symlinks everywhere in project source and dependencies","Avoid postinstall scripts that create absolute links","Vendor dependencies that insist on absolute symlinks","Build from a clean output directory to drop stale links"],"tags":["build","symlink","portability"],"backgroundTag":"absolute-symlink","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}