siyuan-note/siyuan · warning
document changed before hpath refresh completed
Error message
document changed before hpath refresh completed
What it means
After processing all queued sub-document steps of an hpath refresh, refreshHPathsTask re-reads the root block-tree record and compares box, path and hpath with the root snapshot taken when the task started. Any difference means the document changed concurrently while the refresh was running, so applying the remaining work would corrupt the path structure and the task is failed.
Solutions
- Simply retry: the task is marked failed and a new refresh task will be generated for the new hpath — retrigger the rename or run the hpath refresh job again
- Avoid issuing concurrent renames/moves on the same document subtree while a refresh is in progress
- If caused by sync, let sync finish before performing renames, or re-run refresh after sync completes
- Check for automation scripts racing the UI and serialize rename operations
Defensive patterns
Strategy: retry
Try / catch
ok, err := task.refresh(); if err != nil && err.Error() == "document changed before hpath refresh completed" { // retrigger the refresh for the document's current hpath } Prevention
- Avoid renaming the same document repeatedly in quick succession
- Pause sync while performing batch renames via scripts
- Serialize rename/move operations on a subtree
When it happens
Trigger: A rename/move/edit of the root document (changing its BoxID, Path, or HPath) happens between the start of refreshHPathsTask and completion of task.docs processing — e.g. a user renames a parent while the background refresh job is still walking its descendants.
Common situations: Rapid successive renames of parent documents; concurrent API scripts renaming while the UI also modifies the tree; sync applying remote tree changes during a local refresh.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- kernel is exiting
- OIDC configuration changed during provider discovery
- source changed during scan
- workspace changed during asset scan; retry the request
- 0
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/e5c8fffa31246ce5.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/hpath_refresh.go:474
for _, doc := range docs {
task.docs = append(task.docs, doc.ID)
}
task.covers = map[string]*hpathRefreshTask{}
for key, other := range hpathRefresh.tasks {
if other == task || other.Box != root.BoxID {
continue
}
bt := treenode.GetBlockTreeInBox(other.ID, other.Box)
if bt != nil && bt.BoxID == root.BoxID && strings.HasPrefix(bt.Path, strings.TrimSuffix(root.Path, ".sy")+"/") {
task.covers[key] = other
other.coveredBy = task
}
}
}
if task.index >= len(task.docs) {
current := treenode.GetBlockTreeInBox(root.ID, root.BoxID)
if current == nil || current.BoxID != root.BoxID || current.Path != root.Path || current.HPath != root.HPath {
return false, errors.New("document changed before hpath refresh completed")
}
return true, nil
}
doc := treenode.GetBlockTreeInBox(task.docs[task.index], root.BoxID)
if doc == nil || doc.BoxID != root.BoxID || (doc.Path != root.Path && !strings.HasPrefix(doc.Path, strings.TrimSuffix(root.Path, ".sy")+"/")) {
task.index++
task.blockAfter, task.treeAfter = 0, 0
return false, nil
}
fingerprint := sha256.Sum256([]byte(doc.BoxID + "\x00" + doc.Path + "\x00" + doc.HPath))
if task.fingerprint != fingerprint {
task.blockAfter, task.treeAfter = 0, 0
task.fingerprint = fingerprint
}
start := time.Now()
blockAfter, treeAfter, docDone, busy, err := sql.RefreshHPathsBatch(doc, task.blockAfter, task.treeAfter, task.limit)
if err != nil || busy {
return false, errView on GitHub (pinned to 9f775e8a12)