siyuan-note/siyuan · error

invalid encrypted asset metadata size

Error message

invalid encrypted asset metadata size

What it means

After the magic check, decryptAssetMetadata reads the big-endian uint32 metadata length at bytes 4..8 and requires it to be >=1, <= encryptedAssetMetadataMaxSize (1 MiB), and to fit within the ciphertext (8+size+4 <= len). This error means the length field is zero, exceeds the cap, or the container is truncated before the metadata (and trailing 4 bytes) it declares.

Solutions

  1. Restore the asset from sync history or backup — a truncated/corrupted container cannot be repaired in place
  2. Re-encrypt from the original source if available
  3. Validate the container with model.IsEncryptedNotebookData and a length sanity check before calling decrypt paths

Example fix

// before
plain, name, err := model.DecryptAssetWithName(box, disk, dek, data)
// after
if len(data) >= 8 {
    sz := int(binary.BigEndian.Uint32(data[4:8]))
    if sz <= 0 || sz > 1024*1024 || 8+sz+4 > len(data) {
        return errors.New("encrypted asset truncated or corrupt")
    }
}
plain, name, err := model.DecryptAssetWithName(box, disk, dek, data)
Defensive patterns

Strategy: validation

Validate before calling

func containerHeaderSane(data []byte) bool {
    if len(data) < 8 { return false }
    sz := int(binary.BigEndian.Uint32(data[4:8]))
    return sz >= 1 && sz <= 1<<20 && 8+sz+4 <= len(data)
}

Try / catch

plain, name, err := model.DecryptAssetWithName(box, disk, dek, data)
if err != nil && strings.Contains(err.Error(), "invalid encrypted asset metadata size") {
    return restoreAssetFromHistory(box, disk)
}

Prevention

When it happens

Trigger: Decrypting a container whose header was corrupted (length overwritten), a file truncated mid-metadata, or a malicious/crafted file claiming an absurd metadata size; reading a partially synced asset.

Common situations: Interrupted sync or download leaving a truncated container; disk corruption flipping bytes in the length prefix; attempting to decrypt a file that mixes formats.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/9af0c1f04c1ce163. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/crypto.go:2307

		}
		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
}

// encryptedAssetChunkAAD 将分块绑定到本次写入的容器,阻止同名资源的不同版本互换分块。
func encryptedAssetChunkAAD(prefix string, containerID []byte, index uint64) []byte {
	return []byte(fmt.Sprintf("%s:content:v%d:%x:%d", prefix, encryptedAssetSpec, containerID, index))

View on GitHub (pinned to 9f775e8a12)