siyuan-note/siyuan · error
Conf.Language(14) (copy assets failed: %s)
Error message
Conf.Language(14) (copy assets failed: %s)
What it means
When removeAssets is false, ExportDocx copies the temporary assets/ directory next to the exported .docx so embedded images resolve. If filelock.Copy of the assets directory to <savePath>/assets fails, the localized 'Export failed: %s' template is filled with the error and returned.
Source
Thrown at kernel/model/export.go:1175
output, pandocErr := pandoc.CombinedOutput()
if pandocErr != nil {
argStr := strings.Join(args, " ")
msg := gulu.DecodeCmdOutput(output)
logging.LogErrorf("export docx [%s] failed: %s", argStr, msg)
return fmt.Errorf(Conf.Language(14), msg)
}
fullPath = filepath.Join(savePath, name+".docx")
fullPath = util.GetUniqueFilename(fullPath)
if copyErr := filelock.Copy(tmpDocxPath, fullPath); copyErr != nil {
logging.LogErrorf("export docx failed: %s", copyErr)
return fmt.Errorf(Conf.Language(14), copyErr)
}
if tmpAssets := filepath.Join(tmpDir, "assets"); !removeAssets && gulu.File.IsDir(tmpAssets) {
if copyErr := filelock.Copy(tmpAssets, filepath.Join(savePath, "assets")); copyErr != nil {
logging.LogErrorf("export docx failed: %s", copyErr)
return fmt.Errorf(Conf.Language(14), copyErr)
}
}
return nil
})
if err != nil {
fullPath = ""
}
return
}
func ExportMarkdownHTML(id, savePath string, docx, merge bool, mergeHeadingOptions ...MergeHeadingOptions) (name, dom string) {
if err := prepareExportBlockAssets(id, merge); err != nil {
util.PushErrMsg(err.Error(), 7000)
return
}
name, dom, err := exportMarkdownHTML(id, savePath, docx, merge, mergeHeadingOptions...)
if err != nil {
logging.LogErrorf("export markdown html [%s] failed: %s", id, err)View on GitHub (pinned to 8641553a1f)
Solutions
- Ensure no process locks files under <savePath>/assets (close editors, pause cloud sync) and retry.
- Export to a fresh directory instead of one containing a previous assets folder.
- Make existing destination asset files writable or remove the stale assets directory manually.
- Check free disk space and directory write permissions for the save path.
Defensive patterns
Strategy: try-catch
Validate before calling
// preflight: check existing assets dir is writable const assetsDir = savePath + "/assets"; if (await dirExists(assetsDir)) await ensureWritable(assetsDir);
Try / catch
try {
await exportDocx({id, savePath});
} catch (e) {
if (String(e.msg).includes('assets')) {
adviseClearingStaleAssetsDir();
}
} Prevention
- Export to clean directories when possible
- Pause cloud-sync clients that may lock files in the destination assets folder
- Remove read-only flags from previously exported asset files
When it happens
Trigger: filelock.Copy(tmpAssets, filepath.Join(savePath, "assets")) fails: an existing assets directory or files inside it are locked/read-only, disk full, or permission denied on the destination.
Common situations: Destination already contains an assets folder with read-only files (e.g. from a previous export under version control or cloud sync); exporting onto a read-only volume; partial previous export left locked files.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- Conf.Language(14) (copy docx failed: %s)
- copy unused asset [%s] to history failed: %w
- Conf.Language(14) (copy resource failed: %s)
- Export failed: %s
- Please configure [Settings - Export - Pandoc - Path to Pando
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/5e1aabfd0914a418.
Report an issue: GitHub.