siyuan-note/siyuan · error
Cannot be converted to heading when including sub-documents
Error message
Cannot be converted to heading when including sub-documents
What it means
Thrown by Doc2Heading when the source document has a subdirectory on disk (subDir) that is not empty. The subdirectory represents child documents of the source document. Converting a parent document with children into a heading inside another document would orphan those child documents because their parent .sy file would be consumed. The check uses util.IsEmptyDir(subDir) — if the directory exists but is non-empty, the error fires. The message is Conf.Language(20) = "Cannot be converted to heading when including sub-documents".
Source
Thrown at kernel/model/heading.go:195
return
}
FlushTxQueue()
srcTree, _ := LoadTreeByBlockID(srcID)
if nil == srcTree {
err = ErrBlockNotFound
return
}
if IsBoxDoc(srcTree.Box, srcTree.ID) {
err = errors.New(Conf.Language(341))
return
}
subDir := filepath.Join(util.DataDir, srcTree.Box, strings.TrimSuffix(srcTree.Path, ".sy"))
if gulu.File.IsDir(subDir) {
if !util.IsEmptyDir(subDir) {
err = errors.New(Conf.Language(20))
return
}
if removeErr := os.Remove(subDir); nil != removeErr { // 移除空文件夹不会有副作用
logging.LogWarnf("remove empty dir [%s] failed: %s", subDir, removeErr)
}
}
if nil == treenode.GetBlockTree(targetID) {
// 目标块不存在时忽略处理
return
}
targetTree, _ := LoadTreeByBlockID(targetID)
if nil == targetTree {
// 目标块不存在时忽略处理
return
}View on GitHub (pinned to 251596fc0d)
Solutions
- Move or delete all child documents under the source document first, so its subdirectory becomes empty (or is removed), then retry Doc2Heading.
- Alternatively, convert each child document individually rather than converting the parent document that contains them.
- As an API client, check for the existence of child documents before calling Doc2Heading on a parent document.
Defensive patterns
Strategy: validation
Validate before calling
// Check for child documents before calling Doc2Heading
async function hasChildDocuments(srcID) {
// Check if the document has a non-empty subdirectory on disk
const children = await get('/api/filetree/listDocsByPath', { notebook: srcBox, path: srcID })
return children && children.files && children.files.length > 0
}
if (!(await hasChildDocuments(srcID))) {
await post('/api/filetree/doc2Heading', { srcID, targetID, after })
} Prevention
- Move or delete child documents before converting a parent document to a heading.
- Check for sub-documents before attempting Doc2Heading on any document.
- In the UI, warn the user when they attempt Doc2Heading on a document with children.
When it happens
Trigger: Calling POST /api/filetree/doc2Heading with a srcID whose corresponding .sy file has a sibling directory (named after the document ID with .sy stripped) containing child .sy documents. This happens when a user tries to convert a document that has sub-documents (a parent in the document hierarchy) into a heading.
Common situations: User has a document with child documents (created via heading-level nesting or block embeds) and tries to drag it into another document to merge as headings; an API client selects a parent document without checking for children.
Related errors
- The top-level notebook document cannot be removed or moved
- Encrypted notebooks do not support this operation
- Content block with id [%s] not found
- The doc in the user guide does not support sharing to the co
- heading [%s] is a leaf block and cannot have children; to pl
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/9bf64d3bb3998c02.
Report an issue: GitHub.