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

The exporter allows batching resources from one encrypted notebook, but resources must not come from two different encrypted notebooks in a single export. Once an encrypted boxID is recorded, any subsequent resource from a different encrypted box aborts the export, since each encrypted box requires its own decryption context.

Solutions

  1. Split the export into one ExportResources call per encrypted notebook
  2. Group requested resources by boxID before calling ExportResources
  3. Mix encrypted resources with normal-notebook resources is also rejected — keep batches homogeneous

Example fix

// before
ExportResources([]string{"boxA/assets/a.png", "boxB/assets/b.png"}) // both encrypted
// after
ExportResources([]string{"boxA/assets/a.png"})
ExportResources([]string{"boxB/assets/b.png"})
Defensive patterns

Strategy: validation

Validate before calling

function groupByBox(paths) {
  const groups = {};
  for (const p of paths) {
    const box = p.split('/')[0];
    (groups[box] = groups[box] || []).push(p);
  }
  return Object.values(groups); // one ExportResources call per group
}

Try / catch

try { await exportResources(paths); }
catch (e) {
  if (String(e).includes('across encrypted notebook boundaries')) {
    for (const g of groupByBox(paths)) await exportResources(g);
  }
}

Prevention

When it happens

Trigger: ExportResources called with asset paths from two different encrypted notebooks in the same call (boxID extracted from the second path differs from the first).

Common situations: UI multi-select export across notebooks where more than one selected notebook is encrypted; plugin aggregating assets from several encrypted notebooks into one request.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/0bf99ac08cb91838. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/export.go:1018

	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, accessChecker ...EmbedBlockAccessChecker) (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 9f775e8a12)