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) {
		// 目标块不存在时忽略处理
		return

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Pass a child sub-document ID as srcID, not the notebook's root document
  2. Check that srcTree path is not the root (.sy at notebook root) before calling
  3. 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

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


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/7fb883d73ca2d628. Report an issue: GitHub.