siyuan-note/siyuan · error
not a code block
Error message
not a code block
What it means
Returned by ExportCodeBlock when the block referenced by blockID loads successfully but its AST node type is not ast.NodeCodeBlock. The function specifically exports code-block content as a .txt file, so any other block type (paragraph, heading, list, etc.) is rejected. This is a type-mismatch guard, not a corruption indicator.
Source
Thrown at kernel/model/export.go:112
return
}
func ExportCodeBlock(blockID string) (filePath string, err error) {
// Supports exporting a code block as a file https://github.com/siyuan-note/siyuan/pull/16774
err = withExportReadLockByBlockID(blockID, func() error {
tree, _ := LoadTreeByBlockID(blockID)
if nil == tree {
return ErrBlockNotFound
}
node := treenode.GetNodeInTree(tree, blockID)
if nil == node {
return ErrBlockNotFound
}
if ast.NodeCodeBlock != node.Type {
return errors.New("not a code block")
}
code := node.ChildByType(ast.NodeCodeBlockCode)
if nil == code {
return errors.New("code block has no code node")
}
name := tree.Root.IALAttr("title") + "-" + util.CurrentTimeSecondsStr() + ".txt"
name = util.FilterFileName(name)
exportFolder := filepath.Join(util.TempDir, "export")
// 加密笔记本的导出归入 boxID 子目录,确保 LockBox 清理和服务端校验锁定状态
if IsEncryptedBox(tree.Box) {
exportFolder = filepath.Join(exportFolder, tree.Box)
}
exportFolder = filepath.Join(exportFolder, "code")
if mkdirErr := os.MkdirAll(exportFolder, 0755); mkdirErr != nil {
return mkdirErr
}View on GitHub (pinned to 251596fc0d)
Solutions
- Verify the blockID resolves to a NodeCodeBlock before calling ExportCodeBlock — check the block type via the block-tree or SQL.
- Ensure the UI context menu for 'export code block' only appears when the selected block is a code block.
- If exporting arbitrary block content is needed, use the general export functions (Export2HTML/Markdown) instead of ExportCodeBlock.
Example fix
// before
path, err := model.ExportCodeBlock(blockID)
// after — verify type first
bt := treenode.GetBlockTree(blockID)
if bt == nil || bt.Type != "NodeCodeBlock" {
return errors.New("selected block is not a code block")
}
path, err := model.ExportCodeBlock(blockID) Defensive patterns
Strategy: type-guard
Validate before calling
// Verify block is a code block before exporting
bt := treenode.GetBlockTree(blockID)
if bt == nil || bt.Type != "NodeCodeBlock" {
return errors.New("block is not a code block")
} Type guard
func isCodeBlock(blockID string) bool {
bt := treenode.GetBlockTree(blockID)
return bt != nil && bt.Type == "NodeCodeBlock"
} Prevention
- Only show the 'export code block' menu item when the context block is a code block.
- API callers should validate the block type before calling ExportCodeBlock.
- Use general export functions for non-code content.
When it happens
Trigger: ExportCodeBlock is called via the API/UI with a blockID that points to a non-code-block node. The frontend 'export code block' menu item was somehow triggered on a non-code block, or an API caller passed the wrong block ID.
Common situations: API caller passed a document-level block ID instead of the inner code-block ID. Plugin or automation invoked the export endpoint with a paragraph or heading ID. Frontend bug sent the wrong block reference.
Related errors
- code block has no code node
- export source [%s] is not a regular file
- --id is required
- --output is required for docx
- Please unlock the encrypted notebook first
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/568320ebd72f8660.
Report an issue: GitHub.