siyuan-note/siyuan · error

code block has no code node

Error message

code block has no code node

What it means

ExportCodeBlock found a node of type ast.NodeCodeBlock but its ChildByType(ast.NodeCodeBlockCode) returned nil, meaning the code block AST is missing the child node that holds the actual code text. This indicates a malformed or unexpectedly structured code block in the tree — an internal invariant violation rather than normal caller error.

Solutions

  1. Rebuild the tree/index for the document (re-parse the .sy via Lute) and retry.
  2. Open the block in the editor, re-type or re-create the code block, then export again.
  3. Restore the document from history/snapshot if the .sy file is corrupted.
  4. If reproducible from generated input, fix the producer so it emits a NodeCodeBlockCode child.
Defensive patterns

Strategy: try-catch

Validate before calling

node := treenode.GetNodeInTree(tree, blockID)
if node != nil && node.Type == ast.NodeCodeBlock && node.ChildByType(ast.NodeCodeBlockCode) == nil {
    return errors.New("malformed code block; rebuild the document index")
}

Type guard

func hasCodeChild(node *ast.Node) bool { return node != nil && node.ChildByType(ast.NodeCodeBlockCode) != nil }

Try / catch

if err != nil {
    if err.Error() == "code block has no code node" {
        // trigger doc re-index or restore from history
    }
    return err
}

Prevention

When it happens

Trigger: Calling ExportCodeBlock on a code block whose serialized .sy tree lost its NodeCodeBlockCode child — e.g. corrupted/partially written .sy file, a tree produced by an older/abnormal format, or a node constructed by a plugin without the code child.

Common situations: Data corruption or interrupted writes to the .sy file; importing or generating documents programmatically with hand-built ASTs; version changes in the lute AST format.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at kernel/model/export.go:117

	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
		}

		code.Tokens = bytes.ReplaceAll(code.Tokens, []byte(editor.Zwj+"```"), []byte("```"))

		writePath := filepath.Join(exportFolder, name)
		if writeErr := filelock.WriteFile(writePath, code.Tokens); writeErr != nil {

View on GitHub (pinned to 9f775e8a12)