{"record":{"id":"cc30e65d7b7b65f2","repo":"siyuan-note/siyuan","slug":"code-block-has-no-code-node","errorCode":null,"errorMessage":"code block has no code node","messagePattern":"code block has no code node","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/export.go","lineNumber":117,"sourceCode":"\n\terr = withExportReadLockByBlockID(blockID, func() error {\n\t\ttree, _ := LoadTreeByBlockID(blockID)\n\t\tif nil == tree {\n\t\t\treturn ErrBlockNotFound\n\t\t}\n\n\t\tnode := treenode.GetNodeInTree(tree, blockID)\n\t\tif nil == node {\n\t\t\treturn ErrBlockNotFound\n\t\t}\n\n\t\tif ast.NodeCodeBlock != node.Type {\n\t\t\treturn errors.New(\"not a code block\")\n\t\t}\n\n\t\tcode := node.ChildByType(ast.NodeCodeBlockCode)\n\t\tif nil == code {\n\t\t\treturn errors.New(\"code block has no code node\")\n\t\t}\n\n\t\tname := tree.Root.IALAttr(\"title\") + \"-\" + util.CurrentTimeSecondsStr() + \".txt\"\n\t\tname = util.FilterFileName(name)\n\t\texportFolder := filepath.Join(util.TempDir, \"export\")\n\t\t// 加密笔记本的导出归入 boxID 子目录，确保 LockBox 清理和服务端校验锁定状态\n\t\tif IsEncryptedBox(tree.Box) {\n\t\t\texportFolder = filepath.Join(exportFolder, tree.Box)\n\t\t}\n\t\texportFolder = filepath.Join(exportFolder, \"code\")\n\t\tif mkdirErr := os.MkdirAll(exportFolder, 0755); mkdirErr != nil {\n\t\t\treturn mkdirErr\n\t\t}\n\n\t\tcode.Tokens = bytes.ReplaceAll(code.Tokens, []byte(editor.Zwj+\"```\"), []byte(\"```\"))\n\n\t\twritePath := filepath.Join(exportFolder, name)\n\t\tif writeErr := filelock.WriteFile(writePath, code.Tokens); writeErr != nil {","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/export.go#L99-L135","documentation":"Returned by ExportCodeBlock when the node IS a NodeCodeBlock but it has no child of type NodeCodeBlockCode. A well-formed code block in SiYuan's AST always contains a code-content child node; its absence indicates a malformed or corrupted tree — the block was created or migrated incorrectly.","triggerScenarios":"LoadTreeByBlockID returns a tree where the code-block node exists but its child structure is broken (missing NodeCodeBlockCode child). Happens with hand-edited .sy files, buggy import/migration, or partial sync data.","commonSituations":"Imported a Markdown file that produced a partial code-block node. Sync conflict resolution dropped the code-content child. Manual editing of the .sy JSON damaged the tree structure. A very old SiYuan version created the block with a different child layout.","solutions":["Open the document in the SiYuan editor and re-create the code block — the editor will write a well-formed AST.","If the .sy file is hand-edited, ensure the code block node has a child with Type = NodeCodeBlockCode containing the code text in Tokens.","For batch corruption, run the notebook repair/re-index function to rebuild the block tree."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":"path, err := model.ExportCodeBlock(blockID)\nif err != nil {\n    if strings.Contains(err.Error(), \"no code node\") {\n        // malformed AST — guide user to re-create the block\n    }\n    return err\n}","preventionTips":["Avoid hand-editing .sy JSON files.","Run notebook repair/re-index if code blocks are malformed.","After migration/import, spot-check code blocks render correctly before bulk export."],"tags":["export","code-block","ast","corruption","malformed-tree"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}