siyuan-note/siyuan · error
exporting resources across encrypted notebook boundaries is
Error message
exporting resources across encrypted notebook boundaries is not supported
What it means
Returned by exportResourcesEncryptedBox when the resource list contains assets from two or more *different* encrypted notebooks (encryptedBoxID is already set and a later path yields a different encrypted boxID). Cross-notebook encrypted export is refused because each encrypted box has its own DEK and read-lock scope, and the unified export path can only hold one box's lock.
Source
Thrown at kernel/model/export.go:942
for _, resourcePath := range resourcePaths {
resourceFullPath := filepath.Join(util.WorkspaceDir, resourcePath)
if !util.IsAbsPathInWorkspace(resourceFullPath) {
return "", errors.New("resource path [" + resourcePath + "] is not in workspace")
}
boxID := ExtractBoxIDFromAssetsPath(resourceFullPath)
if boxID == "" || !IsEncryptedBox(boxID) {
hasNormalResource = true
continue
}
assetsPath := filepath.Join(util.DataDir, boxID, "assets")
if !gulu.File.IsSubPath(assetsPath, resourceFullPath) {
return "", errors.New("exporting non-asset files from encrypted notebooks is not supported")
}
if encryptedBoxID == "" {
encryptedBoxID = boxID
} else if encryptedBoxID != boxID {
return "", errors.New("exporting resources across encrypted notebook boundaries is not supported")
}
}
if encryptedBoxID != "" && hasNormalResource {
return "", errors.New("exporting encrypted and normal notebook resources together is not supported")
}
return
}
func ExportPreview(id string, fillCSSVar bool) (retStdHTML string) {
if exportErr := withExportReadLockByBlockID(id, func() error {
blockRefMode := Conf.Export.BlockRefMode
bt := getExportBlockTree(id)
if nil == bt {
return nil
}
tree := prepareExportTree(bt)
if numberErr := applyHeadingNumbersForExport(tree, bt, false); nil != numberErr {View on GitHub (pinned to 251596fc0d)
Solutions
- Split the export into separate ExportResources calls, one per encrypted notebook.
- If the assets must be in one archive, first export each box separately then combine the resulting zips outside SiYuan.
- Filter the selection so all encrypted assets come from a single box.
Example fix
// before — mixing two encrypted boxes in one call
model.ExportResources([]string{
"data/boxA/assets/a.png",
"data/boxB/assets/b.png",
}, name)
// after — one encrypted box per call
model.ExportResources([]string{"data/boxA/assets/a.png"}, name)
model.ExportResources([]string{"data/boxB/assets/b.png"}, name) Defensive patterns
Strategy: validation
Validate before calling
// Ensure all encrypted resources belong to a single box
var firstEncBox string
for _, p := range resourcePaths {
full := filepath.Join(util.WorkspaceDir, p)
boxID := ExtractBoxIDFromAssetsPath(full)
if boxID == "" || !IsEncryptedBox(boxID) {
continue
}
if firstEncBox == "" {
firstEncBox = boxID
} else if firstEncBox != boxID {
return errors.New("resources span multiple encrypted notebooks; split the export")
}
} Prevention
- One encrypted notebook per ExportResources call.
- Split multi-box selections before exporting.
- Combine resulting zips outside SiYuan if a single archive is needed.
When it happens
Trigger: POST /api/export/exportResources where resourcePaths mixes assets from data/boxA/assets/ and data/boxB/assets/, both boxA and boxB being encrypted notebooks. Detected when the second distinct encrypted boxID is encountered in the loop.
Common situations: User multi-selects assets across two encrypted notebooks in the UI and chooses 'export resources'. A plugin batches assets from multiple encrypted boxes into one export call.
Related errors
- exporting non-asset files from encrypted notebooks is not su
- exporting encrypted and normal notebook resources together i
- CLI does not support encrypted notebook [%s]
- CLI does not support files in encrypted notebooks
- encrypted notebook is not accessible
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/0bf99ac08cb91838.
Report an issue: GitHub.