siyuan-note/siyuan · error

document [%s] could not be read

Error message

document [%s] could not be read

What it means

ReorderDocTree loads the sibling documents of the target's parent (loadSiblingCustomOrder) and requires that every sibling ID it discovers is present in byID (the freshly loaded sibling records). If a sibling ID from the stored/existing order cannot be resolved to a readable document, the whole reorder is aborted with this error. It prevents persisting a sort order over a stale sibling set containing deleted or unreadable documents.

Source

Thrown at kernel/model/file_tree_reorder.go:145

	}
	// 隐藏文档和超过显示上限的文档也必须参与排序。
	docs, _, err := ListDocTree(box.ID, listPath, mode, false, true, int(^uint(0)>>1))
	if err != nil {
		return nil, err
	}
	byID := map[string]*File{}
	currentIDs := make([]string, 0, len(docs))
	for _, doc := range docs {
		byID[doc.ID] = doc
		currentIDs = append(currentIDs, doc.ID)
	}
	siblingIDs, err := loadSiblingCustomOrder(box.ID, parentDir, existingSorts)
	if err != nil {
		return nil, err
	}
	for _, id := range siblingIDs {
		if byID[id] == nil {
			return nil, fmt.Errorf("document [%s] could not be read", id)
		}
	}
	var fromPaths []string
	for _, id := range sourceIDs {
		source := treenode.GetBlockTree(id)
		if !isSortableDocument(source) || Conf.Box(source.BoxID) == nil {
			return nil, fmt.Errorf("source document [%s] is unavailable", id)
		}
		if source.BoxID == target.BoxID && (target.Path == source.Path ||
			strings.HasPrefix(target.Path, strings.TrimSuffix(source.Path, ".sy")+"/")) {
			return nil, fmt.Errorf("cannot move document [%s] into itself", id)
		}
		if byID[id] != nil {
			continue
		}
		sourceParent := path.Dir(source.Path)
		if sourceParent != "/" {
			sourceParent += ".sy"

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Delete or clean the stale entries in <data>/<boxID>/.siyuan/sort.json so the sibling list matches existing docs
  2. Run a reindex: POST /api/filetree/refreshFiletree (or restart the kernel) to reconcile the index with disk
  3. Restore the missing document (from SiYuan history or sync snapshot) if it should still exist
  4. Check file permissions on the parent directory so the kernel can read all .sy files
  5. Retry the reorder once the sibling list is consistent

Example fix

// before (sort.json references a deleted doc id 20240101120000-abcd123)
{"sorts": {"parentPath": ["20240101120000-abcd123", "20240101120001-defg456"]}}
// after (removed the orphaned id so reorder can proceed)
{"sorts": {"parentPath": ["20240101120001-defg456"]}}
Defensive patterns

Strategy: validation

Validate before calling

// Ensure stored custom order has no orphan ids before reordering
const siblings = await fetchPost('/api/filetree/listDocsByPath', {notebook: boxId, path: parentPath});
const live = new Set(siblings.data.files.map(f => f.id));
// any id in sort.json not in `live` is a stale entry needing cleanup/reindex

Try / catch

try {
  await fetchPost('/api/filetree/reorderDocs', {sourceIDs, targetID, position});
} catch (e) {
  if (String(e).includes('could not be read')) {
    await fetchPost('/api/filetree/refreshFiletree', {}); // reconcile index with disk, then retry
  }
}

Prevention

When it happens

Trigger: The stored sort.json or block-tree sibling list contains an ID whose .sy file is missing, unreadable, or was removed from the index (deleted on another device, failed sync, partial index rebuild) while ReorderDocTree is computing the new order.

Common situations: sort.json left over from documents deleted via external file edits; sync conflicts leaving orphaned IDs in the custom order; index corruption after crash where the doc file is gone but the ID remains in stored order config.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/fe0071ff7464f5f5. Report an issue: GitHub.