siyuan-note/siyuan · error

invalid encrypted asset format

Error message

invalid encrypted asset format

What it means

Thrown by decryptAssetMetadata when the ciphertext is shorter than 8 bytes or does not begin with the 4-byte magic 'SYAE' (0x53 0x59 0x41 0x45). This means the input is not a SiYuan encrypted asset container at all — it is either a plaintext asset, a truncated file, or a foreign format.

Source

Thrown at kernel/model/crypto.go:2265

			[]byte(fmt.Sprintf("%s:content:%d", aadPrefix, 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
	}
	metadata = &encryptedAssetMetadata{}
	if err = json.Unmarshal(plainMetadata, metadata); err != nil {
		return nil, 0, err
	}
	if metadata.OriginalName == "" || metadata.OriginalName == "." ||
		filepath.Base(metadata.OriginalName) != metadata.OriginalName || strings.ContainsAny(metadata.OriginalName, `/\`) {

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Check whether the file starts with the SYAE magic bytes before attempting decryption; if not, treat it as plaintext.
  2. Re-run the encryption migration for the notebook to convert any remaining plaintext assets.
  3. Restore the asset from a known-good backup if it is truncated or corrupted.

Example fix

// before
plain, err := DecryptAsset(boxID, diskName, dek, raw)
// after
if len(raw) < 8 || !bytes.Equal(raw[:4], encryptedAssetMagic) {
    // not an encrypted asset — handle as plaintext
    plain = raw
} else {
    plain, err = DecryptAsset(boxID, diskName, dek, raw)
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Check for SYAE magic before decrypting
var encryptedAssetMagic = []byte{'S', 'Y', 'A', 'E'}
if len(raw) >= 4 && bytes.Equal(raw[:4], encryptedAssetMagic) {
    plain, err = DecryptAsset(boxID, diskName, dek, raw)
} else {
    plain = raw // plaintext asset
}

Type guard

func isEncryptedAsset(data []byte) bool {
    magic := []byte{'S', 'Y', 'A', 'E'}
    return len(data) >= 8 && bytes.Equal(data[:4], magic)
}

Prevention

When it happens

Trigger: DecryptAsset / DecryptAssetWithName / copyAssetDecryptIfEncrypted is invoked on a file that is not in the SYAE encrypted format. Happens when IsEncryptedBox(boxID) returned true but the specific asset file on disk was never encrypted (e.g., written before encryption was enabled, or placed manually).

Common situations: User enabled encryption on an existing notebook, but some assets predate the encryption migration and remain as plaintext files. File was partially downloaded/restored from a corrupted backup. A sync conflict left a plaintext copy in an encrypted notebook's assets directory.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/d07c17c2b7fa3fe8. Report an issue: GitHub.