siyuan-note/siyuan · error

Conf.Language(180)

Error message

Conf.Language(180)

What it means

validateFlashcardBlockIDs reports, through the localized message Conf.Language(180), that one of the requested block IDs does not exist in the block tree (treenode.GetBlockTree returned nil). Flashcards can only be created or operated on for blocks the kernel has indexed.

Source

Thrown at kernel/model/flashcard.go:52

	"github.com/siyuan-note/filelock"
	"github.com/siyuan-note/logging"
	"github.com/siyuan-note/riff"
	"github.com/siyuan-note/siyuan/kernel/cache"
	"github.com/siyuan-note/siyuan/kernel/sql"
	"github.com/siyuan-note/siyuan/kernel/treenode"
	"github.com/siyuan-note/siyuan/kernel/util"
)

// ValidateFlashcardBlockIDs 只允许普通笔记本中可确认存在的块进入全局闪卡存储。
func ValidateFlashcardBlockIDs(blockIDs []string) error {
	return validateFlashcardBlockIDs(blockIDs, treenode.GetBlockTree, IsEncryptedBox)
}

func validateFlashcardBlockIDs(blockIDs []string, getBlockTree func(string) *treenode.BlockTree, isEncryptedBox func(string) bool) error {
	for _, blockID := range blockIDs {
		bt := getBlockTree(blockID)
		if bt == nil {
			return errors.New(Conf.Language(180))
		}
		if isEncryptedBox(bt.BoxID) {
			return errors.New(Conf.Language(313))
		}
	}
	return nil
}

func validateFlashcardTree(rootID string) error {
	return ValidateFlashcardBlockIDs([]string{rootID})
}

func isSupportedFlashcardBlock(blockID string) bool {
	bt := treenode.GetBlockTreeInExactBox(blockID, "")
	return bt != nil && !IsEncryptedBox(bt.BoxID)
}

func filterSupportedFlashcards(cards []riff.Card) (ret []riff.Card) {

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Verify the block ID exists: query the block (SQL `SELECT * FROM blocks WHERE id = ?`) or open it in the editor before calling flashcard APIs.
  2. Rebuild the index so the block is present in the block tree.
  3. Filter out invalid IDs client-side and retry with only existing blocks.
  4. Refresh IDs if the source block was deleted or its content changed.

Example fix

// before
await addRiffCards([maybeDeletedID])
// after
const existing = await fetchPost('/api/query/sql', { stmt: "SELECT id FROM blocks WHERE id='" + id + "'" })
if (existing.length) await addRiffCards([id])
Defensive patterns

Strategy: validation

Validate before calling

const res = await fetchPost('/api/query/sql', { stmt: "SELECT id FROM blocks WHERE id IN ('" + ids.join("','") + "')" })
const valid = ids.filter(id => res.some(r => r.id === id))

Try / catch

try {
  await addRiffCards(ids)
} catch (e) {
  if (String(e.msg).includes(Lang180)) showMsg('One or more blocks no longer exist', 'error')
  else throw e
}

Prevention

When it happens

Trigger: Calling ValidateFlashcardBlockIDs (or flashcard APIs like adding/removing/RESET that validate block IDs) with an ID absent from blocktree.db — unindexed block, wrong notebook, or stale ID.

Common situations: Plugin passes a block ID from a different workspace; the block was deleted after the ID was captured; the notebook was not yet indexed (first sync after import); mobile/external edits made before indexing finished.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/b0cf3508d61df6f6. Report an issue: GitHub.