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
- Verify the block ID exists: query the block (SQL `SELECT * FROM blocks WHERE id = ?`) or open it in the editor before calling flashcard APIs.
- Rebuild the index so the block is present in the block tree.
- Filter out invalid IDs client-side and retry with only existing blocks.
- 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
- Resolve IDs through the SQL/block API right before flashcard calls
- Refresh IDs after deletes, renames, or sync
- Ensure the notebook has been indexed before operating on its blocks
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
- Encrypted notebooks do not support this operation
- invalid relation block ID [%s]
- view [%s] not found in attribute view [%s]
- attribute view [%s] is not bound
- previous attribute view [%s] is not bound
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/b0cf3508d61df6f6.
Report an issue: GitHub.