{"record":{"id":"9bf64d3bb3998c02","repo":"siyuan-note/siyuan","slug":"cannot-be-converted-to-heading-when-including-sub","errorCode":null,"errorMessage":"Cannot be converted to heading when including sub-documents","messagePattern":"Cannot be converted to heading when including sub-documents","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/heading.go","lineNumber":195,"sourceCode":"\t\treturn\n\t}\n\n\tFlushTxQueue()\n\n\tsrcTree, _ := LoadTreeByBlockID(srcID)\n\tif nil == srcTree {\n\t\terr = ErrBlockNotFound\n\t\treturn\n\t}\n\tif IsBoxDoc(srcTree.Box, srcTree.ID) {\n\t\terr = errors.New(Conf.Language(341))\n\t\treturn\n\t}\n\n\tsubDir := filepath.Join(util.DataDir, srcTree.Box, strings.TrimSuffix(srcTree.Path, \".sy\"))\n\tif gulu.File.IsDir(subDir) {\n\t\tif !util.IsEmptyDir(subDir) {\n\t\t\terr = errors.New(Conf.Language(20))\n\t\t\treturn\n\t\t}\n\n\t\tif removeErr := os.Remove(subDir); nil != removeErr { // 移除空文件夹不会有副作用\n\t\t\tlogging.LogWarnf(\"remove empty dir [%s] failed: %s\", subDir, removeErr)\n\t\t}\n\t}\n\n\tif nil == treenode.GetBlockTree(targetID) {\n\t\t// 目标块不存在时忽略处理\n\t\treturn\n\t}\n\n\ttargetTree, _ := LoadTreeByBlockID(targetID)\n\tif nil == targetTree {\n\t\t// 目标块不存在时忽略处理\n\t\treturn\n\t}","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/heading.go#L177-L213","documentation":"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\".","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Check for child documents before calling Doc2Heading\nasync function hasChildDocuments(srcID) {\n  // Check if the document has a non-empty subdirectory on disk\n  const children = await get('/api/filetree/listDocsByPath', { notebook: srcBox, path: srcID })\n  return children && children.files && children.files.length > 0\n}\nif (!(await hasChildDocuments(srcID))) {\n  await post('/api/filetree/doc2Heading', { srcID, targetID, after })\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["heading","doc-conversion","sub-documents","restriction"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}