siyuan-note/siyuan · error
exporting symbolic links is not supported
Error message
exporting symbolic links is not supported
What it means
Returned by copyExportResource when os.Lstat on the top-level resource path shows the ModeSymlink bit set. SiYuan refuses to export symlinks because a symlink can point outside the workspace (and outside an encrypted notebook's assets dir), which would leak plaintext paths or escape the workspace sandbox. The check uses Lstat, so the link itself (not its target) is inspected.
Source
Thrown at kernel/model/export.go:863
}
exportFilePath = path.Join("temp", "export")
if encryptedBoxID != "" {
exportFilePath = path.Join("temp", "export", registerManagedEncryptedExport(encryptedBoxID, "resources", zipFilePath))
} else {
exportFilePath = path.Join(exportFilePath, filepath.Base(zipFilePath))
}
return
}
// copyExportResource 复制导出资源,目录逐文件处理以避免将加密资源作为普通文件读取。
func copyExportResource(source, destination string) error {
info, err := os.Lstat(source)
if err != nil {
return err
}
if info.Mode()&os.ModeSymlink != 0 {
return errors.New("exporting symbolic links is not supported")
}
if !info.IsDir() {
return copyExportFile(source, destination)
}
return filepath.WalkDir(source, func(current string, entry fs.DirEntry, walkErr error) error {
if walkErr != nil {
return walkErr
}
if entry.Type()&os.ModeSymlink != 0 {
return errors.New("exporting symbolic links is not supported")
}
relativePath, relErr := filepath.Rel(source, current)
if relErr != nil {
return relErr
}
target := filepath.Join(destination, relativePath)
if entry.IsDir() {View on GitHub (pinned to 251596fc0d)
Solutions
- Replace the symlink with the actual file or a copy of its target inside the workspace, then export.
- Resolve the symlink to its real target and ensure that target is a regular file or directory inside the workspace before exporting.
- Avoid storing symlinks inside the SiYuan assets folder — copy real files instead.
- If using a sync client, configure it to materialize files rather than leave symlink placeholders.
Example fix
# before — assets/myvideo is a symlink to /mnt/external/clip.mp4 ls -la workspace/data/notebook/assets/myvideo # after — replace symlink with the real file (or a copy) rm workspace/data/notebook/assets/myvideo cp /mnt/external/clip.mp4 workspace/data/notebook/assets/myvideo
Defensive patterns
Strategy: validation
Validate before calling
// Reject symlinks before calling ExportResources
for _, p := range resourcePaths {
full := filepath.Join(util.WorkspaceDir, p)
if info, err := os.Lstat(full); err == nil && info.Mode()&os.ModeSymlink != 0 {
return fmt.Errorf("refusing to export symlink: %s", p)
}
} Type guard
// isRegularOrRealDir reports whether the path is a real file/dir (not a symlink).
func isRegularOrRealDir(p string) bool {
info, err := os.Lstat(p)
if err != nil {
return false
}
return info.Mode()&os.ModeSymlink == 0
} Prevention
- Do not store symlinks inside the SiYuan assets folder; copy real files.
- Resolve symlinks to their targets and ensure targets are regular files inside the workspace.
- Configure sync clients to materialize files rather than leave symlink placeholders.
When it happens
Trigger: ExportResources called with a resource path that is itself a symbolic link. Common on Linux/macOS where users symlink asset folders into the workspace, or where a sync tool replaced a file with a symlink.
Common situations: User created a symlink inside the workspace assets folder pointing to an external directory. A cloud-sync client (Dropbox/OneDrive) represented a placeholder file as a symlink. Migrating data via symlinks.
Related errors
- resource path [%s] is not in workspace
- exporting special files is not supported
- export source [%s] is not a regular file
- refuse to write decrypted asset inside workspace
- source is not an encrypted asset
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/97253987903676ba.
Report an issue: GitHub.