siyuan-note/siyuan · error

source document [%s] could not be read

Error message

source document [%s] could not be read

What it means

After loading the sibling list of the source document's parent folder, ReorderDocTree could not find the requested source document ID among its siblings. This means the block-tree entry exists but the actual document file/listing is missing or unreadable, so a custom sort order involving it cannot be applied.

Source

Thrown at kernel/model/file_tree_reorder.go:176

		if byID[id] != nil {
			continue
		}
		sourceParent := path.Dir(source.Path)
		if sourceParent != "/" {
			sourceParent += ".sy"
		}
		sourceDocs, _, loadErr := ListDocTree(source.BoxID, sourceParent, util.SortModeCustom, false, true, int(^uint(0)>>1))
		if loadErr != nil {
			return nil, loadErr
		}
		for _, doc := range sourceDocs {
			if doc.ID == id {
				byID[id] = doc
				break
			}
		}
		if byID[id] == nil {
			return nil, fmt.Errorf("source document [%s] could not be read", id)
		}
		currentIDs = append(currentIDs, id)
		fromPaths = append(fromPaths, source.Path)
	}
	orderedIDs, changed, err := reorderIDSequence(currentIDs, sourceIDs, targetID, position)
	if err != nil {
		return nil, err
	}
	ret = &DocTreeReorderResult{Changed: changed || len(fromPaths) > 0, Notebook: box.ID, ParentPath: listPath}
	for i := 1; i < len(orderedIDs); i++ {
		if fileTreeSortLess(byID[orderedIDs[i]], byID[orderedIDs[i-1]], mode) {
			ret.Conflict = true
			break
		}
	}
	if preview || !ret.Changed || ret.Conflict && !removeSorts {
		return ret, nil
	}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Verify the source document file exists on disk under the notebook's data folder and re-run the operation.
  2. Rebuild the index (Settings - Rebuild Index / full-text rebuild) so block-tree entries match actual files.
  3. Re-fetch the document list and use current IDs before reordering.
  4. If a sibling listed in the saved custom order is unreadable, clean up stale entries in the sibling order (loadSiblingCustomOrder path reports the same class of problem).

Example fix

// before
await reorderDocTree(boxID, [staleDocID], targetID, position)
// after
const docs = await listDocs(boxID, parentPath)
const validIDs = sourceIDs.filter(id => docs.some(d => d.id === id))
if (validIDs.length === sourceIDs.length) {
  await reorderDocTree(boxID, sourceIDs, targetID, position)
}
Defensive patterns

Strategy: validation

Validate before calling

const docs = await listDocs(boxID, parentPath)
const allPresent = sourceIDs.every(id => docs.some(d => d.id === id))
if (!allPresent) { /* refresh IDs or abort */ }

Try / catch

try {
  await reorderDocTree(boxID, sourceIDs, targetID, position)
} catch (e) {
  if (String(e.msg).includes('could not be read')) { await refreshDocList(); retry() }
  else throw e
}

Prevention

When it happens

Trigger: Calling ReorderDocTree with a source ID whose parent's ListDocTree listing does not contain that ID — e.g. the .sy file was deleted, moved, or is excluded from the listing after the block-tree row was read.

Common situations: A race between index and filesystem (document removed while reorder is in flight); corrupted or out-of-sync blocktree.db; notebooks copied manually so index entries point at nonexistent files; scripts holding stale IDs.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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