siyuan-note/siyuan · error

encrypted notebook [%s] has no valid identity

Error message

encrypted notebook [%s] has no valid identity

What it means

Thrown by validateImportedNotebookIdentities when the conf.json marks the notebook as encrypted (Encrypted: true) but no valid encryption identity can be found. The kernel first tries BoxCrypt from conf.json (if it passes validateBoxEncryption), then falls back to the backup file. If both are nil or invalid, the notebook has no way to unwrap its DEK, making its content permanently inaccessible. The import is refused to avoid importing unrecoverable data.

Source

Thrown at kernel/model/import.go:1077

		}

		var backup *conf.BoxEncryption
		if filelock.IsExist(backupPath) {
			backup, err = readBoxEncryptionFile(backupPath)
			if err != nil {
				return nil, fmt.Errorf("invalid imported notebook identity [%s]: %w", boxID, err)
			}
		}

		var boxCrypt *conf.BoxEncryption
		if boxConf != nil && boxConf.Encrypted {
			if boxConf.BoxCrypt != nil && validateBoxEncryption(boxConf.BoxCrypt) == nil {
				boxCrypt = boxConf.BoxCrypt
			} else {
				boxCrypt = backup
			}
			if boxCrypt == nil {
				return nil, fmt.Errorf("encrypted notebook [%s] has no valid identity", boxID)
			}
		} else if boxConf != nil && backup != nil {
			return nil, fmt.Errorf("notebook [%s] has conflicting normal and encrypted identities", boxID)
		} else if backup != nil {
			boxCrypt = backup
		}

		payloadFound, payloadErr := hasEncryptedNotebookPayloadAtPath(boxDir)
		if payloadErr != nil {
			return nil, fmt.Errorf("inspect imported notebook [%s] failed: %w", boxID, payloadErr)
		}
		if boxCrypt == nil && payloadFound {
			return nil, fmt.Errorf("imported notebook [%s] contains encrypted payload without identity", boxID)
		}
		if boxCrypt == nil {
			continue
		}

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Re-export the Data.zip ensuring the .siyuan/ directory with encryption identity files is included.
  2. Verify the source SiYuan version matches the target version (encryption identity format must be compatible).
  3. If the source notebook is truly encrypted but identity is lost, the data is unrecoverable — re-export from a backup that includes the identity.
  4. If encryption was never intended, edit the conf.json in the Data.zip to set Encrypted to false before importing.
Defensive patterns

Strategy: validation

Validate before calling

// Check that encrypted notebooks in the archive have encryption identity
func checkEncryptedNotebookIdentity(tmpDataPath, boxID string) error {
    confPath := filepath.Join(tmpDataPath, boxID, ".siyuan", "conf.json")
    backupPath := filepath.Join(tmpDataPath, boxID, ".siyuan", notebookCryptoBackupFilename)
    if !filelock.IsExist(confPath) {
        return nil
    }
    data, _ := filelock.ReadFile(confPath)
    boxConf := conf.NewBoxConf()
    if err := gulu.JSON.UnmarshalJSON(data, boxConf); err != nil {
        return err
    }
    if !boxConf.Encrypted {
        return nil
    }
    if boxConf.BoxCrypt != nil && validateBoxEncryption(boxConf.BoxCrypt) == nil {
        return nil
    }
    if !filelock.IsExist(backupPath) {
        return fmt.Errorf("encrypted notebook %s has no identity and no backup", boxID)
    }
    return nil
}

Try / catch

encryptedBoxIDs, err := validateImportedNotebookIdentities(tmpDataPath)
if err != nil {
    if strings.Contains(err.Error(), "has no valid identity") {
        // Cannot recover — data would be inaccessible
        return fmt.Errorf("encrypted notebook identity is missing; re-export with .siyuan/ directory")
    }
}

Prevention

When it happens

Trigger: Calling validateImportedNotebookIdentities where boxConf.Encrypted is true, but both boxConf.BoxCrypt is nil-or-invalid AND the backup file is nil-or-absent. The check is at import.go:1070-1078.

Common situations: Exporting from a SiYuan version that stored encryption identity in a different location than the current version expects. Partial export that omitted the .siyuan/ directory or the backup file. Manual deletion of encryption files from the Data.zip. Conf.json edited to set Encrypted=true without providing BoxCrypt.

Related errors


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