siyuan-note/siyuan · error

not a code block

Error message

not a code block

What it means

ExportCodeBlock exports a code block's content as a .txt file. Before exporting it checks that the node resolved from the tree is actually of type ast.NodeCodeBlock; if the blockID points to any other node type (paragraph, heading, table, etc.) it returns errors.New("not a code block"). The API contract simply does not apply to non-code blocks.

Solutions

  1. Check the block type before calling: load the tree node and confirm it is a code block.
  2. In the UI, only invoke the code-block export action from a code block's menu context.
  3. For batch exports, filter IDs by type via SQL (type = 'NodeCodeBlock') before calling the API.

Example fix

// before
ExportCodeBlock(anyBlockID)
// after
if node := treenode.GetNodeInTree(tree, blockID); node != nil && node.Type == ast.NodeCodeBlock {
    ExportCodeBlock(blockID)
}
Defensive patterns

Strategy: validation

Validate before calling

node := treenode.GetNodeInTree(tree, blockID)
if node == nil || node.Type != ast.NodeCodeBlock {
    return errors.New("block is not a code block")
}
filePath, err := model.ExportCodeBlock(blockID)

Type guard

func isCodeBlock(node *ast.Node) bool { return node != nil && node.Type == ast.NodeCodeBlock }

Try / catch

if err != nil {
    if err.Error() == "not a code block" {
        // fall back to another export path for non-code blocks
    }
    return err
}

Prevention

When it happens

Trigger: Calling ExportCodeBlock(blockID) with a blockID that exists in the tree but whose node.Type != ast.NodeCodeBlock — e.g. passing a document ID, heading ID, or paragraph ID.

Common situations: Frontend/plugin code assumes the focused block is a code block; stale IDs after the block was converted to another type; batch export scripts iterating block IDs without filtering by type.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/568320ebd72f8660. Report an issue: GitHub.

Appendix: 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 9f775e8a12)