siyuan-note/siyuan · error

notebook [%s] has conflicting normal and encrypted identitie

Error message

notebook [%s] has conflicting normal and encrypted identities

What it means

Thrown by validateImportedNotebookIdentities when the conf.json explicitly marks the notebook as NOT encrypted (Encrypted: false or absent), but a backup encryption file (notebookCryptoBackupFilename) exists in .siyuan/. This is a contradictory state: the notebook claims to be a normal notebook, yet it carries encrypted-notebook identity artifacts. The import is refused to prevent silently treating encrypted data as plaintext or vice versa.

Source

Thrown at kernel/model/import.go:1080

		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
		}

		if err = validateBoxEncryption(boxCrypt); err != nil {
			return nil, fmt.Errorf("invalid imported notebook identity [%s]: %w", boxID, err)
		}

View on GitHub (pinned to 251596fc0d)

Solutions

  1. If the notebook is genuinely not encrypted, remove the .siyuan/<backup-filename> from the Data.zip before importing.
  2. If the notebook IS encrypted, fix the conf.json to set Encrypted: true and ensure BoxCrypt is populated.
  3. Re-export from the source SiYuan to get a consistent state.
  4. Manually reconcile the conf.json and backup file to agree on encryption status before importing.
Defensive patterns

Strategy: validation

Validate before calling

// Check for identity conflicts before importing
func checkIdentityConflict(tmpDataPath, boxID string) error {
    confPath := filepath.Join(tmpDataPath, boxID, ".siyuan", "conf.json")
    backupPath := filepath.Join(tmpDataPath, boxID, ".siyuan", notebookCryptoBackupFilename)
    if !filelock.IsExist(confPath) || !filelock.IsExist(backupPath) {
        return nil
    }
    data, _ := filelock.ReadFile(confPath)
    boxConf := conf.NewBoxConf()
    if err := gulu.JSON.UnmarshalJSON(data, boxConf); err != nil {
        return err
    }
    if !boxConf.Encrypted {
        return fmt.Errorf("notebook %s: conf says not encrypted but backup exists — conflict", boxID)
    }
    return nil
}

Try / catch

encryptedBoxIDs, err := validateImportedNotebookIdentities(tmpDataPath)
if err != nil {
    if strings.Contains(err.Error(), "conflicting normal and encrypted identities") {
        // Suggest removing the backup file or fixing conf.json
        boxID := extractBoxID(err.Error())
        backupPath := filepath.Join(tmpDataPath, boxID, ".siyuan", notebookCryptoBackupFilename)
        if !model.IsEncryptedBox(boxID) {
            os.Remove(backupPath) // remove stale backup
        }
    }
}

Prevention

When it happens

Trigger: Calling validateImportedNotebookIdentities where boxConf exists with Encrypted == false, AND backup != nil (backup file exists and was successfully read). The check is at import.go:1079-1080.

Common situations: Manual editing of conf.json to remove the Encrypted flag while leaving the backup file. A notebook that was decrypted but the backup file was not cleaned up. Version migration that changed how encryption state is tracked. Export from a SiYuan version that handled encryption state differently.

Related errors


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