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
- Verify the source document file exists on disk under the notebook's data folder and re-run the operation.
- Rebuild the index (Settings - Rebuild Index / full-text rebuild) so block-tree entries match actual files.
- Re-fetch the document list and use current IDs before reordering.
- 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
- Fetch current document IDs immediately before reordering
- Rebuild the index if block-tree and files may be out of sync
- Avoid reordering while sync/other sessions may delete documents concurrently
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
- parse json [%s] to tree failed: %w
- encrypted .sy [%s]: base id [%s] != root id [%s]
- target document [%s] is unavailable
- document [%s] could not be read
- source document [%s] is unavailable
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/e455b8e1cbfb90cd.
Report an issue: GitHub.