siyuan-note/siyuan · error

block [ ] is not a document that can declare a child…

Error message

block [%s] is not a document that can declare a child document sort mode

What it means

SetDocSortMode only works on blocks that ARE documents (the tree root, of type NodeDocument) and that live in an opened, non-closed notebook (IsBoxDoc). If the given id does not resolve to such a document, this error is thrown. It guards the document-level sort declaration feature against being applied to ordinary blocks or closed notebooks.

Solutions

  1. Verify the ID is a document ID (load the .sy tree and check the root node type is NodeDocument) before calling
  2. Check that the notebook containing the document is open in the workspace (not in the closed notebooks list)
  3. Re-resolve the ID from the UI/API tree listing rather than a stale cached value
  4. If targeting a non-document block, remove the call — sort mode can only be declared on documents

Example fix

// before
SetDocSortMode(blockID, intPtr(mode)) // blockID may be a child block
// after
if docID, ok := resolveDocumentID(blockID); ok {
    SetDocSortMode(docID, intPtr(mode))
}
Defensive patterns

Strategy: validation

Validate before calling

const doc = await getDocTreeItem(id)
if (!doc || doc.type !== "document" || !isNotebookOpen(doc.notebookId)) throw new Error("not a document in an open notebook")

Type guard

const isDocumentBlock = (b) => !!b && b.type === "NodeDocument" && b.rootId === b.id

Try / catch

try { await api.setDocSortMode(id, mode) } catch (e) { if (String(e).includes("is not a document")) { /* re-resolve the doc ID from the tree */ } else throw e }

Prevention

When it happens

Trigger: Calling SetDocSortMode with the ID of a heading, paragraph, or child block; passing a document ID whose notebook is closed; passing an ID that does not exist at all (LoadTree succeeds but tree.ID/tree.Root.ID mismatch checks fail).

Common situations: Plugins grabbing the wrong selected node ID (e.g. inner block instead of the doc); notebooks closed/unloaded after a workspace switch; IDs copied from search results pointing at non-document blocks.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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

Appendix: source

Thrown at kernel/model/file.go:2509

	ID                string `json:"id"`
	Path              string `json:"path"`
	SortMode          *int   `json:"sortMode"`
	EffectiveSortMode int    `json:"effectiveSortMode"`
}

// SetDocSortMode 设置文档对子文档列表声明的排序方式,sortMode 为 nil 时恢复继承。
func SetDocSortMode(id string, sortMode *int) (ret *DocSortModeResult, err error) {
	if nil != sortMode && !IsValidDocSortMode(*sortMode) {
		return nil, fmt.Errorf("invalid document sort mode [%d]", *sortMode)
	}

	FlushTxQueue()
	tree, err := LoadTreeByBlockID(id)
	if nil != err {
		return nil, err
	}
	if tree.ID != id || tree.Root.ID != id || ast.NodeDocument != tree.Root.Type || IsBoxDoc(tree.Box, tree.ID) {
		return nil, fmt.Errorf("block [%s] is not a document that can declare a child document sort mode", id)
	}

	value := ""
	if nil != sortMode {
		value = strconv.Itoa(*sortMode)
	}
	if tree.Root.IALAttr(DocSortModeAttr) != value {
		if err = setNodeAttrs(tree.Root, tree, map[string]string{DocSortModeAttr: value}); nil != err {
			return nil, err
		}
	}

	effectiveSortMode, resolveErr := ResolveDocTreeSortMode(tree.Box, tree.Path)
	if nil != resolveErr {
		return nil, resolveErr
	}
	ret = &DocSortModeResult{
		Box:               tree.Box,

View on GitHub (pinned to 9f775e8a12)