siyuan-note/siyuan · error
block [%s] is not a sortable document
Error message
block [%s] is not a sortable document
What it means
Thrown by SetFileTreeSort when a docSorts entry passes the existence check but the block is not a root document node. Three conditions are checked: bt.ID must equal bt.RootID (the block must be a document root, not a child block within a document), bt.Type must be "d" (document node type), and IsBoxDoc(bt.BoxID, bt.RootID) must be false (the block must not be a notebook's top-level box document). Only true child documents within a notebook can be reordered via the sort API.
Source
Thrown at kernel/model/file.go:2615
}
docPlans := make([]*docSortPlan, 0, len(docSorts))
docIDs := map[string]struct{}{}
for _, item := range docSorts {
if nil == item {
return ret, errors.New("document sort item must not be nil")
}
if _, ok := docIDs[item.ID]; ok {
return ret, fmt.Errorf("duplicate document ID [%s]", item.ID)
}
docIDs[item.ID] = struct{}{}
bt := treenode.GetBlockTree(item.ID)
if nil == bt || nil == openedBoxes[bt.BoxID] {
return ret, fmt.Errorf("document [%s] not found in opened and unlocked notebooks", item.ID)
}
if bt.ID != bt.RootID || "d" != bt.Type || IsBoxDoc(bt.BoxID, bt.RootID) {
return ret, fmt.Errorf("block [%s] is not a sortable document", item.ID)
}
if nil == boxes[bt.BoxID] {
return ret, fmt.Errorf("notebook [%s] not found for document [%s]", bt.BoxID, item.ID)
}
docPlans = append(docPlans, &docSortPlan{item: item, boxID: bt.BoxID, parentPath: path.Dir(bt.Path)})
}
docGroups := map[string]*docSortGroup{}
for _, plan := range docPlans {
group := docGroups[plan.boxID]
if nil == group {
confPath := filepath.Join(util.DataDir, plan.boxID, ".siyuan", "sort.json")
fullSortIDs, readErr := readSortConfMap(confPath)
if readErr != nil {
return ret, readErr
}
group = &docSortGroup{
fullSortIDs: fullSortIDs,View on GitHub (pinned to 251596fc0d)
Solutions
- Ensure every ID in docSorts is a document root block ID (where block ID == root ID), not a child block within a document.
- Exclude notebook top-level documents (box docs) from docSorts — their position is determined by notebookSorts, not document sorting.
- If building an API client, verify each ID via the block info endpoint and confirm type is document ("d") and ID == rootID before submitting.
Example fix
// before
await post('/api/filetree/setFileTreeSort', {
notebookSorts: [],
docSorts: [{ id: someChildBlockId, sort: 1 }]
})
// after — only sort document root blocks, never child blocks or box docs
await post('/api/filetree/setFileTreeSort', {
notebookSorts: [],
docSorts: [{ id: docRootId, sort: 1 }]
}) Defensive patterns
Strategy: validation
Validate before calling
// Verify each docSorts ID is a document root (not a child block or box doc)
function isSortableDocument(bt) {
return bt && bt.id === bt.rootID && bt.type === 'd' && !bt.isBoxDoc
}
const sortableDocSorts = docSorts.filter(item => isSortableDocument(blockInfo[item.id])) Type guard
// Type guard: check if a block is a sortable document root
function isSortableDocumentRoot(bt: { id: string; rootID: string; type: string; isBoxDoc?: boolean }): boolean {
return bt.id === bt.rootID && bt.type === 'd' && !bt.isBoxDoc
} Prevention
- Only include document root block IDs (where block ID == root ID) in docSorts.
- Never include notebook top-level documents (box docs) in document-level sort operations.
- Verify block type is 'd' before including in sort payloads.
When it happens
Trigger: Calling POST /api/filetree/setFileTreeSort with a docSorts entry whose ID is: (a) a child block within a document (e.g. a paragraph or heading block ID rather than a document root ID), (b) a non-document node, or (c) the top-level box document of a notebook. The box document is the notebook's root .sy file and its sort position is fixed.
Common situations: An API client passes a block ID that is a heading or paragraph rather than a document; the UI incorrectly includes a notebook's top-level document in a sub-document sort operation; an external tool fabricates block IDs that happen to be child blocks.
Related errors
- duplicate notebook ID [%s]
- notebook [%s] not found
- duplicate document ID [%s]
- document [%s] not found in opened and unlocked notebooks
- notebook [%s] not found for document [%s]
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/4d52619bd5038ff4.
Report an issue: GitHub.