siyuan-note/siyuan · error
target document [%s] is unavailable
Error message
target document [%s] is unavailable
What it means
ReorderDocTree validates that the reorder target document exists in the block tree, is a sortable document, and belongs to a notebook currently known to the kernel (Conf.Box). If any of these fail, it returns this error instead of reordering. It protects against reordering around a target that is deleted, moved, corrupted in the index, or in a notebook that is closed.
Source
Thrown at kernel/model/file_tree_reorder.go:111
inherited, err := ResolveDocTreeSortMode(boxID, parentPath)
if err != nil {
return nil, err
}
if inherited == util.SortModeCustom {
return nil, nil
}
return &mode, nil
}
// ReorderDocTree 在移动前检查完整列表,确认冲突后仅设置目标列表的排序方式。
func ReorderDocTree(sourceIDs []string, targetID, position string, preview, removeSorts bool) (ret *DocTreeReorderResult, err error) {
if err = validateReorderArgs(sourceIDs, targetID, position); err != nil {
return
}
FlushTxQueue()
target := treenode.GetBlockTree(targetID)
if !isSortableDocument(target) || Conf.Box(target.BoxID) == nil {
return nil, fmt.Errorf("target document [%s] is unavailable", targetID)
}
box := Conf.Box(target.BoxID)
parentDir := path.Dir(target.Path)
confPath := filepath.Join(util.DataDir, box.ID, ".siyuan", "sort.json")
existingSorts, err := readSortConfMap(confPath)
if err != nil {
return nil, err
}
listPath := parentDir
if listPath != "/" {
listPath += ".sy"
}
mode, err := ResolveDocTreeSortMode(box.ID, listPath)
if err != nil {
return nil, err
}
// 隐藏文档和超过显示上限的文档也必须参与排序。
docs, _, err := ListDocTree(box.ID, listPath, mode, false, true, int(^uint(0)>>1))View on GitHub (pinned to 8641553a1f)
Solutions
- Confirm the target document exists and refresh: POST /api/filetree/getDoc with targetID
- Re-open the target notebook (POST /api/notebook/openNotebook) if it was closed
- Call POST /api/filetree/refreshFiletree or restart sync to rebuild the block-tree index, then retry
- Verify targetID is a full 22-character block ID of an existing .sy document
- Re-check the doc tree listing to obtain a valid current target ID before reordering
Example fix
// before (target deleted by sync between drag and drop)
await fetchPost('/api/filetree/reorderDocs', {sourceIDs, targetID: draggedOverID, position});
// after (guard on live tree data)
const tree = await fetchPost('/api/filetree/listDocsByPath', {notebook, path: parentPath});
if (!tree.data.files.some(f => f.id === draggedOverID)) {
return showError('Target document no longer exists');
}
await fetchPost('/api/filetree/reorderDocs', {sourceIDs, targetID: draggedOverID, position}); Defensive patterns
Strategy: validation
Validate before calling
async function canReorder(targetId) {
const r = await fetchPost('/api/filetree/getDocInfo', {id: targetId});
return r && r.data && r.data.id === targetId;
}
if (!(await canReorder(targetId))) await refreshFiletree(); Type guard
function isFullBlockId(v) { return typeof v === 'string' && /^[0-9]{14}-[a-z0-9]{7}$/.test(v); } Try / catch
try {
await fetchPost('/api/filetree/reorderDocs', {sourceIDs, targetID, position});
} catch (e) {
if (String(e).includes('target document') && String(e).includes('unavailable')) {
await fetchPost('/api/filetree/refreshFiletree', {});
showMsg('Target document is gone; tree refreshed', true);
}
} Prevention
- Ensure the target notebook is open before reordering its documents
- Refresh the filetree after any external edit/sync before reorder operations
- Validate target IDs exist immediately before the reorder call
- Avoid operating on documents mid-sync; wait for sync completion
When it happens
Trigger: Calling ReorderDocTree (or reorderDocs API path) with targetID that has no block-tree record (deleted/unindexed doc), is not a sortable document (e.g. a special/system path), or whose notebook is closed or removed (Conf.Box returns nil).
Common situations: Drag-drop onto a document deleted by another client or sync between drag start and drop; notebook closed while the tree view still shows its docs; stale tree cache after bulk reorganization; targetID typo in API scripts.
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
- source document [%s] is unavailable
- document [%s] could not be read
- Query notebook failed
- document not found or empty
- block not found: %s
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/0c597390c3cf44bd.
Report an issue: GitHub.