stablyai/orca · error · Error

Symlink not allowed in '${entry.name}'

Error message

Symlink not allowed in '${entry.name}'

What it means

Thrown in recursiveCopyDir during local external import. After readdir lists entries, each entry is lstat'd; if the result is a symbolic link, the copy aborts. Local import policy rejects symlinks entirely because cross-platform symlink semantics differ and following links can escape the dropped subtree.

Source

Thrown at src/main/ipc/filesystem-mutations.ts:695

    }
  }
  return false
}

/**
 * Recursively copy a directory and all its contents. Uses copyFile for
 * individual files to leverage native OS copy primitives instead of
 * buffering entire files into memory.
 */
async function recursiveCopyDir(srcDir: string, destDir: string): Promise<void> {
  await mkdir(destDir, { recursive: false })
  const entries = await readdir(srcDir, { withFileTypes: true })
  for (const entry of entries) {
    const srcPath = join(srcDir, entry.name)
    const dstPath = join(destDir, entry.name)
    const statResult = await lstat(srcPath)
    if (statResult.isSymbolicLink()) {
      throw new Error(`Symlink not allowed in '${entry.name}'`)
    }
    if (statResult.isDirectory()) {
      await recursiveCopyDir(srcPath, dstPath)
      continue
    }
    if (!statResult.isFile()) {
      throw new Error(`Unsupported file type in '${entry.name}'`)
    }
    await copyLocalFileNoFollow(srcPath, dstPath, statResult)
  }
}

async function copyLocalFileNoFollow(
  srcPath: string,
  dstPath: string,
  statResult?: Awaited<ReturnType<typeof lstat>>
): Promise<void> {
  const beforeOpenStat = statResult ?? (await lstat(srcPath))

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Remove or resolve symlinks in the source directory before importing.
  2. Use `find /source -type l` to identify all symlinks, then decide which to remove or dereference.
  3. If pnpm/yarn symlinks are the cause, run `pnpm install` or `yarn install` on the destination after importing the non-symlink files.

Example fix

// before: import /project containing symlink node_modules/.pnpm
// after: dereference or remove symlinks first
//   find /project -type l -delete   # remove symlinks
//   or: cp -rL /project /resolved-project  # dereference, then import /resolved-project
Defensive patterns

Strategy: validation

Validate before calling

const { readdir, lstat } = await import('node:fs/promises')
const { join } = await import('node:path')

async function findSymlinks(dir: string): Promise<string[]> {
  const links: string[] = []
  async function visit(d: string): Promise<void> {
    for (const entry of await readdir(d, { withFileTypes: true })) {
      const p = join(d, entry.name)
      const st = await lstat(p)
      if (st.isSymbolicLink()) links.push(p)
      else if (st.isDirectory()) await visit(p)
    }
  }
  await visit(dir)
  return links
}
// const links = await findSymlinks(sourceDir)
// if (links.length) throw new Error(`Remove symlinks first: ${links.join(', ')}`)

Try / catch

try {
  await importLocalSource(sourcePath, destDir)
} catch (error) {
  if (error instanceof Error && error.message.startsWith('Symlink not allowed')) {
    showUserError(`${error.message} — remove or dereference the symlink and retry.`)
    return
  }
  throw error
}

Prevention

When it happens

Trigger: Importing a local directory that contains a symlink. The lstat on a child entry returns isSymbolicLink() true, triggering the rejection before any copy attempt.

Common situations: Importing a project directory containing node_modules symlinks (pnpm, yarn workspaces). Importing a directory with config symlinks (e.g., .bashrc -> dotfiles/repo). macOS app bundles that use symlinks internally. Imported folder from a Linux environment where symlinks are common.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/0e04a89c6e8f5128. Report an issue: GitHub.