siyuan-note/siyuan · error
invalid encrypted asset format
Error message
invalid encrypted asset format
What it means
decryptAssetMetadata validates that the ciphertext starts with the 8-byte header: the 4-byte magic 'SYAE' plus at least 8 total bytes to read the metadata length. This error means the byte slice is not a recognizable encrypted-asset container — wrong magic or too-short input.
Solutions
- Verify the file is a genuine encrypted asset: first 4 bytes must be 'S','Y','A','E' (use model.IsEncryptedNotebookData as a pre-check)
- Re-download or restore the asset from sync/history — the local copy is likely truncated or corrupted
- Re-encrypt the original source with EncryptAsset instead of decrypting a non-encrypted file
Example fix
// before
plain, name, err := model.DecryptAssetWithName(box, disk, dek, data)
// after
if len(data) < 8 || string(data[:4]) != "SYAE" {
return errors.New("not an encrypted asset container")
}
plain, name, err := model.DecryptAssetWithName(box, disk, dek, data) Defensive patterns
Strategy: type-guard
Validate before calling
func isEncryptedAssetContainer(data []byte) bool {
return len(data) >= 8 && bytes.Equal(data[:4], []byte("SYAE"))
} Type guard
func looksLikeEncryptedAsset(r io.Reader) (bool, error) {
head := make([]byte, 4)
if _, err := io.ReadFull(r, head); err != nil {
return false, err
}
if seeker, ok := r.(io.Seeker); ok { seeker.Seek(0, io.SeekStart) }
return bytes.Equal(head, []byte("SYAE")), nil
} Try / catch
plain, name, err := model.DecryptAssetWithName(box, disk, dek, data)
if err != nil && strings.Contains(err.Error(), "invalid encrypted asset format") {
return readUnencryptedAsset(data) // fall back to plain path
} Prevention
- Use model.IsEncryptedNotebookData(data) to pick the encrypted vs plain read path before decrypting
- Verify file sizes after sync/download to catch truncation early
- Do not mix notebook-level ciphertext and asset-container bytes in the same storage field
When it happens
Trigger: Decrypting (via DecryptAssetWithName / DecryptAssetToWriter / metadata readers) a blob shorter than 8 bytes or not beginning with bytes 'SYAE'; passing plaintext file content, a truncated/corrupted file, or data encrypted by a different scheme (e.g. whole-notebook ciphertext without the asset magic).
Common situations: Pointing asset decryption at a non-encrypted asset file; truncated download/sync leaving a partial container; version mismatch where an old file layout predates the SYAE magic; hand-edited or corrupted .sy-referenced assets.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- invalid encrypted asset metadata size
- invalid encrypted asset chunk count
- invalid encrypted asset content metadata
- invalid encrypted envelope nonce length
- 26
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/d07c17c2b7fa3fe8.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/crypto.go:2303
encryptedAssetChunkAAD(aadPrefix, containerID, chunkIndex),
)
if encryptErr != nil {
return nil, encryptErr
}
if err = binary.Write(ret, binary.BigEndian, uint32(len(encryptedChunk))); err != nil {
return nil, err
}
ret.Write(encryptedChunk)
}
if err = binary.Write(ret, binary.BigEndian, uint32(0)); err != nil {
return nil, err
}
return ret.Bytes(), nil
}
func decryptAssetMetadata(boxID, diskName string, dek, ciphertext []byte) (metadata *encryptedAssetMetadata, contentOffset int, err error) {
if len(ciphertext) < 8 || !bytes.Equal(ciphertext[:4], encryptedAssetMagic) {
return nil, 0, errors.New("invalid encrypted asset format")
}
metadataSize := int(binary.BigEndian.Uint32(ciphertext[4:8]))
if metadataSize < 1 || metadataSize > encryptedAssetMetadataMaxSize || 8+metadataSize+4 > len(ciphertext) {
return nil, 0, errors.New("invalid encrypted asset metadata size")
}
assetKey := util.DeriveSubKey(dek, "siyuan/asset")
defer zeroAndClear(assetKey)
aadPrefix := "siyuan:asset:" + boxID + ":assets/" + diskName
plainMetadata, decryptErr := util.DecryptWithAAD(assetKey, ciphertext[8:8+metadataSize], []byte(aadPrefix+":metadata"))
if decryptErr != nil {
return nil, 0, decryptErr
}
defer zeroAndClear(plainMetadata)
if metadata, err = parseEncryptedAssetMetadata(plainMetadata); err != nil {
return nil, 0, err
}
return metadata, 8 + metadataSize, nil
}View on GitHub (pinned to 9f775e8a12)