siyuan-note/siyuan · warning

managed export is unavailable

Error message

managed export is unavailable

What it means

When the requested export file name belongs to a managed encrypted export path, `ResolveManagedEncryptedExport` must map it back to a live box/artifact. This error means the name has the managed prefix but no matching managed export registration exists — the artifact record is gone or was never registered.

Source

Thrown at kernel/model/encrypted_export.go:191

	}
	return filepath.FromSlash(strings.Join(parts, "/"))
}

// AcquireExportArtifactLease 为导出产物取得覆盖整个复制过程的生命周期租约。
func AcquireExportArtifactLease(exportPath string) (lease *ExportArtifactLease, err error) {
	if after, ok := strings.CutPrefix(exportPath, "/export/"); ok {
		fileName, decodeErr := url.PathUnescape(after)
		if decodeErr != nil {
			return nil, decodeErr
		}
		fileName = filepath.Clean(fileName)
		if fileName == "." || strings.HasPrefix(fileName, "..") || filepath.IsAbs(fileName) {
			return nil, errors.New("invalid export path")
		}
		if IsManagedEncryptedExportPath(fileName) {
			boxID, artifact, resolved := ResolveManagedEncryptedExport(fileName)
			if !resolved {
				return nil, errors.New("managed export is unavailable")
			}
			if err = AcquireEncryptedBoxOperation(boxID); err != nil {
				return nil, err
			}
			HoldBoxReadLock(boxID)
			release := true
			defer func() {
				if release {
					ReleaseBoxReadLock(boxID)
					ReleaseEncryptedBoxOperation(boxID)
				}
			}()
			_, artifact, resolved = ResolveManagedEncryptedExport(fileName)
			if !resolved {
				return nil, errors.New("managed export is unavailable")
			}
			if _, dekErr := GetDEKIfUnlocked(boxID); dekErr != nil {
				return nil, dekErr

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Re-run the export to produce a fresh managed export path, then request the lease with the new name.
  2. Verify the source notebook is unlocked — managed resolution requires the box to still be registered.
  3. Clear the stale reference in the client and re-navigate from the export result instead of a cached URL.
  4. If this happens right after restart, re-trigger the export since managed registrations are in-memory.

Example fix

// before
leaseFromOldManagedName("export/managed-abc123.html") // stale after restart
// after
const exported = await runExport(boxID) // returns fresh managed name
leaseFromOldManagedName(exported.managedName)
Defensive patterns

Strategy: retry

Try / catch

lease, err := model.AcquireExportArtifactLease(name)
if err != nil && err.Error() == "managed export is unavailable" {
    // regenerate the export and retry with the fresh managed name
    fresh := regenerateExport(boxID)
    lease, err = model.AcquireExportArtifactLease(fresh)
}

Prevention

When it happens

Trigger: AcquireExportArtifactLease called with a managed export path for which ResolveManagedEncryptedExport returns resolved=false (first lookup, before any lease is held).

Common situations: Requesting an export lease for an artifact whose registration expired or was cleared after kernel restart; a client retrying with an old managed file name after the export was regenerated; typo'd managed path.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/2ac72ee36965310b. Report an issue: GitHub.