siyuan-note/siyuan · error

Conf.Language(385)

Error message

Conf.Language(385)

What it means

checkEncryptedImportDeck rejects importing flashcard deck data (storage/riff) into an encrypted notebook. When the packaged deck cannot be loaded/parsed, no specific documents can be identified, so the error (i18n key 385) reports the archive-internal deck path storage/riff instead. Import is refused because deck scheduling depends on the global database.

Solutions

  1. Import into a non-encrypted notebook, where deck data is supported
  2. Fix or regenerate the storage/riff deck data in the source notebook and re-export
  3. Remove the storage/riff directory from the archive if the flashcards are not needed
Defensive patterns

Strategy: validation

Validate before calling

import fs from "fs";
const riffDir = path.join(extractedRoot, "storage", "riff");
if (targetNotebook.encrypted && fs.existsSync(riffDir)) {
  throw new Error("Archive contains flashcard deck data; encrypted notebook import is not supported");
}

Type guard

const hasDeckData = (root) => { try { return require("fs").existsSync(require("path").join(root, "storage", "riff")); } catch { return false; } };

Try / catch

try {
  await importSY(zipPath, boxID, toPath, createNotebook, autoDetect);
} catch (e) {
  if (e.message.includes("storage/riff") || /385|deck/i.test(e.message)) {
    console.warn("Flashcard deck data cannot be imported into an encrypted notebook; import into a plain notebook or strip storage/riff");
  } else { throw e; }
}

Prevention

When it happens

Trigger: Importing a .sy.zip that contains a storage/riff directory into an encrypted notebook when riff.LoadDeck fails or returns a nil deck (corrupt or unreadable deck data).

Common situations: Corrupted or hand-edited storage/riff deck files inside an exported notebook archive; deck format produced by a different SiYuan version; importing flashcard-bearing notebook exports into encrypted notebooks.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at kernel/model/import.go:372

		})
	}
	return ret
}

// checkEncryptedImportDeck 检查导入包里的闪卡数据。
// 加密笔记本是孤岛,闪卡牌组与调度依赖全局数据库,因此必须拒绝导入;
// 报错会指出包内哪些文档的卡片位于牌组中,便于用户在源笔记本中移除闪卡后重新导出。
func checkEncryptedImportDeck(unzipRootPath string, trees map[string]*parse.Tree, blockIDs map[string]string) error {
	storageRiffDir := filepath.Join(unzipRootPath, "storage", "riff")
	if !gulu.File.IsExist(storageRiffDir) {
		return nil
	}

	deck, loadErr := riff.LoadDeck(storageRiffDir, builtinDeckID, Conf.Flashcard.RequestRetention, Conf.Flashcard.MaximumInterval, Conf.Flashcard.Weights)
	if nil != loadErr || nil == deck {
		// 牌组无法解析时仍要拒绝导入,此时无法指出具体文档,只报告包内牌组路径
		logging.LogErrorf("load imported deck [%s] failed: %s", storageRiffDir, loadErr)
		return errors.New(fmt.Sprintf(Conf.Language(385), filepath.ToSlash(filepath.Join("storage", "riff"))))
	}

	var deckDocs []string
	blockDocTitles := importedBlockDocTitles(trees)
	for _, blockID := range deck.GetBlockIDs() {
		// 卡片记录的是导出时的旧块 ID,需按导入时重建的映射换算
		newBlockID := blockIDs[blockID]
		if "" == newBlockID {
			newBlockID = blockID
		}
		if title := blockDocTitles[newBlockID]; "" != title {
			deckDocs = append(deckDocs, title)
		} else {
			// 卡片所属块不在本次导入范围内,保留块 ID 供用户定位
			deckDocs = append(deckDocs, newBlockID)
		}
	}
	if 0 == len(deckDocs) {

View on GitHub (pinned to 9f775e8a12)