siyuan-note/siyuan · critical

encrypted notebook [ ] has no valid identity

Error message

encrypted notebook [%s] has no valid identity

What it means

For a notebook whose conf.json declares Encrypted=true, validateImportedNotebookIdentities needs a usable BoxEncryption identity: prefer a validated boxConf.BoxCrypt, otherwise fall back to the backup file. If neither is present or valid, it returns 'encrypted notebook [%s] has no valid identity', refusing the import — importing an encrypted notebook without its key envelope would produce permanently unreadable content.

Solutions

  1. Re-export/re-package the notebook from the source workspace including the full .siyuan directory so BoxCrypt/backup key material is present.
  2. Restore the notebook's encryption backup file from sync history or snapshots, then retry the import.
  3. If the notebook should be plaintext, decrypt it in the source workspace first (with its keys available there), then re-export and import.
  4. Never regenerate MasterSalt or key material to force the import — recover the original keys via the recovery phrase instead.
Defensive patterns

Strategy: validation

Validate before calling

const conf = JSON.parse(await fs.promises.readFile(path.join(boxDir, '.siyuan', 'conf.json'), 'utf8'));
const hasBackup = fs.existsSync(path.join(boxDir, '.siyuan', notebookCryptoBackupFilename));
if (conf.encrypted && !conf.boxCrypt && !hasBackup) {
  throw new Error('encrypted notebook package lacks key material; re-export with .siyuan included');
}

Try / catch

try {
  await importData(src);
} catch (e) {
  if (/has no valid identity/.test(e.msg)) {
    console.error('Re-export including encryption metadata, or restore the backup file / recover keys via recovery phrase');
  }
  throw e;
}

Prevention

When it happens

Trigger: ImportData importing a notebook with conf.json {"encrypted": true} but with a missing/nil BoxCrypt field AND a missing or invalid encryption backup file, so no validated identity can be established.

Common situations: 1) User hand-copied only the .sy files, omitting .siyuan encryption metadata. 2) Archive builder excluded hidden .siyuan directory. 3) Backup file exists but failed validation (see index 1496) so the fallback is nil. 4) Notebook encrypted after export; archive predates encryption.

Related errors


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

Appendix: source

Thrown at kernel/model/import.go:1360

		}

		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 9f775e8a12)