siyuan-note/siyuan · error
decrypt file annotation
Error message
decrypt file annotation [%s]: %w
What it means
For assets in encrypted notebooks, the .sya annotation data is ciphertext and is decrypted with the notebook's data-encryption key via DecryptAsset. If decryption or authentication fails (wrong key, corrupted or tampered ciphertext, version mismatch), the export aborts with this wrapped error instead of falling back to plaintext, per the encrypted-notebook compatibility policy.
Solutions
- Restore the correct notebook encryption keys (do not regenerate MasterSalt); keep keys consistent between devices
- Re-sync the notebook from a healthy replica to replace corrupted ciphertext
- Verify the .sya resides in the same notebook it was encrypted for; move it back if misplaced
- Ensure the kernel version supports the .sya envelope format version, or migrate via the supported recovery path
Example fix
// before: .sya copied into another encrypted notebook -> decrypt fails assets/report.pdf.sya (in box-B, encrypted for box-A) // after: keep sidecar with its owning notebook assets/report.pdf.sya (in box-A)
Defensive patterns
Strategy: try-catch
Try / catch
try {
await exportAnnotation(docID);
} catch (e) {
if (/decrypt file annotation/.test(e.message)) {
// do NOT retry with regenerated keys; restore keys from a working replica first
await restoreKeysFromReplica(boxID);
return exportAnnotation(docID);
}
throw e;
} Prevention
- Never regenerate MasterSalt or delete the keys folder to 'fix' decryption errors
- Keep keys and encrypted data in sync together across devices
- Never copy .sya sidecars between different encrypted notebooks
- Keep the kernel updated so supported envelope formats remain readable
When it happens
Trigger: Exporting an annotation from a notebook whose MasterSalt/keys were regenerated or lost; .sya ciphertext corrupted by partial sync or manual editing; DecryptAsset rejects the payload because the basename or AAD does not match what was authenticated at write time.
Common situations: Workspace keys folder restored from an old backup while data came from a newer sync; user copied a .sya into a different encrypted notebook; truncated/corrupted file after an interrupted transfer; decrypting an asset that was written under an older envelope format version without its migration path.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- Conf.Language(314)
- Conf.Language(314)
- Conf.Language(314)
- Conf.Language(314)
- invalid file annotation reference
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/13f814b38047582c.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/export.go:4379
assetBoxID := ExtractBoxIDFromAssetsPath(absPath)
var dek []byte
if IsEncryptedBox(assetBoxID) {
HoldBoxReadLock(assetBoxID)
defer ReleaseBoxReadLock(assetBoxID)
dek, err = GetDEKIfUnlocked(assetBoxID)
if err != nil {
return err
}
defer clear(dek)
}
syaData, readErr := os.ReadFile(sya)
if readErr != nil {
return fmt.Errorf("read file annotation [%s]: %w", sya, readErr)
}
if nil != dek {
plain, decErr := DecryptAsset(assetBoxID, filepath.Base(sya), dek, syaData)
if decErr != nil {
return fmt.Errorf("decrypt file annotation [%s]: %w", sya, decErr)
}
syaData = plain
}
syaJSON := map[string]struct {
Pages []struct {
Index *int `json:"index"`
} `json:"pages"`
Page *int `json:"page"`
}{}
if err = gulu.JSON.UnmarshalJSON(syaData, &syaJSON); err != nil {
return fmt.Errorf("parse file annotation [%s]: %w", sya, err)
}
annotationData, found := syaJSON[annotationID]
pageIndex := annotationData.Page
if 0 < len(annotationData.Pages) {
pageIndex = annotationData.Pages[0].Index
}
if !found || nil == pageIndex || *pageIndex < 0 {View on GitHub (pinned to 9f775e8a12)