{"record":{"id":"b0cf3508d61df6f6","repo":"siyuan-note/siyuan","slug":"conf-language-180","errorCode":null,"errorMessage":"Conf.Language(180)","messagePattern":"Conf\\.Language\\(180\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/flashcard.go","lineNumber":52,"sourceCode":"\t\"github.com/siyuan-note/filelock\"\n\t\"github.com/siyuan-note/logging\"\n\t\"github.com/siyuan-note/riff\"\n\t\"github.com/siyuan-note/siyuan/kernel/cache\"\n\t\"github.com/siyuan-note/siyuan/kernel/sql\"\n\t\"github.com/siyuan-note/siyuan/kernel/treenode\"\n\t\"github.com/siyuan-note/siyuan/kernel/util\"\n)\n\n// ValidateFlashcardBlockIDs 只允许普通笔记本中可确认存在的块进入全局闪卡存储。\nfunc ValidateFlashcardBlockIDs(blockIDs []string) error {\n\treturn validateFlashcardBlockIDs(blockIDs, treenode.GetBlockTree, IsEncryptedBox)\n}\n\nfunc validateFlashcardBlockIDs(blockIDs []string, getBlockTree func(string) *treenode.BlockTree, isEncryptedBox func(string) bool) error {\n\tfor _, blockID := range blockIDs {\n\t\tbt := getBlockTree(blockID)\n\t\tif bt == nil {\n\t\t\treturn errors.New(Conf.Language(180))\n\t\t}\n\t\tif isEncryptedBox(bt.BoxID) {\n\t\t\treturn errors.New(Conf.Language(313))\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc validateFlashcardTree(rootID string) error {\n\treturn ValidateFlashcardBlockIDs([]string{rootID})\n}\n\nfunc isSupportedFlashcardBlock(blockID string) bool {\n\tbt := treenode.GetBlockTreeInExactBox(blockID, \"\")\n\treturn bt != nil && !IsEncryptedBox(bt.BoxID)\n}\n\nfunc filterSupportedFlashcards(cards []riff.Card) (ret []riff.Card) {","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/flashcard.go#L34-L70","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait addRiffCards([maybeDeletedID])\n// after\nconst existing = await fetchPost('/api/query/sql', { stmt: \"SELECT id FROM blocks WHERE id='\" + id + \"'\" })\nif (existing.length) await addRiffCards([id])","handlingStrategy":"validation","validationCode":"const res = await fetchPost('/api/query/sql', { stmt: \"SELECT id FROM blocks WHERE id IN ('\" + ids.join(\"','\") + \"')\" })\nconst valid = ids.filter(id => res.some(r => r.id === id))","typeGuard":null,"tryCatchPattern":"try {\n  await addRiffCards(ids)\n} catch (e) {\n  if (String(e.msg).includes(Lang180)) showMsg('One or more blocks no longer exist', 'error')\n  else throw e\n}","preventionTips":["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"],"tags":["flashcards","entity-not-found","block-id","spaced-repetition"],"backgroundTag":"entity-not-found","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}