siyuan-note/siyuan · error
Conf.Language(341)
Error message
Conf.Language(341)
What it means
Doc2Heading converts a document into heading content merged under a target heading. Before doing anything it refuses when the source tree IS the notebook's own top-level document (IsBoxDoc): Conf.Language(341) — 'The top-level notebook document cannot be removed or moved'. The operation would delete/move the notebook's root document, which is not allowed.
Source
Thrown at kernel/model/heading.go:188
}()
}
return
}
func Doc2Heading(srcID, targetID string, after bool) (srcTreeBox, srcTreePath string, err error) {
if !ast.IsNodeIDPattern(srcID) || !ast.IsNodeIDPattern(targetID) {
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) {
// 目标块不存在时忽略处理
returnView on GitHub (pinned to 8641553a1f)
Solutions
- Pass a child sub-document ID as srcID, not the notebook's root document
- Check that srcTree path is not the root (.sy at notebook root) before calling
- Choose a different organization (rename or move the notebook) instead of converting the root doc
Example fix
// before
await fetchPost('/api/filetree/doc2Heading', {srcID: rootDocID, targetID: headingID});
// after
if (rootDocID === srcID) throw new Error('top-level doc cannot be converted');
await fetchPost('/api/filetree/doc2Heading', {srcID: subDocID, targetID: headingID}); Defensive patterns
Strategy: validation
Validate before calling
// root doc of a notebook has path == '/<rootDocID>.sy'; refuse conversion
const doc = getDocMeta(srcID);
if (doc.path === `/${doc.rootID}.sy`) throw new Error('cannot convert top-level notebook document'); Try / catch
try {
await fetchPost('/api/filetree/doc2Heading', {srcID, targetID});
} catch (e) {
if (String(e.msg).includes('top-level notebook document')) {
alert('Choose a sub-document instead of the notebook root');
} else throw e;
} Prevention
- Only offer the 'convert to heading' action on non-root documents in UI
- Compare doc.path against the notebook root pattern before calling
- Remember top-level docs also cannot be removed or moved
When it happens
Trigger: Calling Doc2Heading (API doc2HeadingHeadingTransaction) where srcID refers to the notebook's root/top-level document rather than a sub-document.
Common situations: Selecting the whole notebook root in a script or UI automation and invoking the merge-to-heading action; misidentifying the srcID by passing the doc that equals the notebook path root.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Conf.Language(20)
- Query notebook failed
- Encrypted notebooks do not support this operation
- Please specify the daily note save path in the Notebook Sett
- The top-level notebook document cannot be removed or moved
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/7fb883d73ca2d628.
Report an issue: GitHub.