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

  1. Verify the file is a genuine encrypted asset: first 4 bytes must be 'S','Y','A','E' (use model.IsEncryptedNotebookData as a pre-check)
  2. Re-download or restore the asset from sync/history — the local copy is likely truncated or corrupted
  3. 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

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


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)