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
- Verify the ID is a document ID (load the .sy tree and check the root node type is NodeDocument) before calling
- Check that the notebook containing the document is open in the workspace (not in the closed notebooks list)
- Re-resolve the ID from the UI/API tree listing rather than a stale cached value
- 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
- Resolve document IDs from the file-tree listing API, not from arbitrary block selections
- Re-check notebook open state after workspace switches
- Cache document IDs only with a freshness policy tied to sync events
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
- block [ ] is not a document
- Conf.Language(112)
- duplicate source ID [ ]
- invalid appearance ID
- invalid document sort mode
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)