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

  1. Ensure every ID in docSorts is a document root block ID (where block ID == root ID), not a child block within a document.
  2. Exclude notebook top-level documents (box docs) from docSorts — their position is determined by notebookSorts, not document sorting.
  3. 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

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


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/4d52619bd5038ff4. Report an issue: GitHub.