{"record":{"id":"e5c8fffa31246ce5","repo":"siyuan-note/siyuan","slug":"document-changed-before-hpath-refresh-completed","errorCode":null,"errorMessage":"document changed before hpath refresh completed","messagePattern":"document changed before hpath refresh completed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kernel/model/hpath_refresh.go","lineNumber":474,"sourceCode":"\t\tfor _, doc := range docs {\n\t\t\ttask.docs = append(task.docs, doc.ID)\n\t\t}\n\t\ttask.covers = map[string]*hpathRefreshTask{}\n\t\tfor key, other := range hpathRefresh.tasks {\n\t\t\tif other == task || other.Box != root.BoxID {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tbt := treenode.GetBlockTreeInBox(other.ID, other.Box)\n\t\t\tif bt != nil && bt.BoxID == root.BoxID && strings.HasPrefix(bt.Path, strings.TrimSuffix(root.Path, \".sy\")+\"/\") {\n\t\t\t\ttask.covers[key] = other\n\t\t\t\tother.coveredBy = task\n\t\t\t}\n\t\t}\n\t}\n\tif task.index >= len(task.docs) {\n\t\tcurrent := treenode.GetBlockTreeInBox(root.ID, root.BoxID)\n\t\tif current == nil || current.BoxID != root.BoxID || current.Path != root.Path || current.HPath != root.HPath {\n\t\t\treturn false, errors.New(\"document changed before hpath refresh completed\")\n\t\t}\n\t\treturn true, nil\n\t}\n\tdoc := treenode.GetBlockTreeInBox(task.docs[task.index], root.BoxID)\n\tif doc == nil || doc.BoxID != root.BoxID || (doc.Path != root.Path && !strings.HasPrefix(doc.Path, strings.TrimSuffix(root.Path, \".sy\")+\"/\")) {\n\t\ttask.index++\n\t\ttask.blockAfter, task.treeAfter = 0, 0\n\t\treturn false, nil\n\t}\n\tfingerprint := sha256.Sum256([]byte(doc.BoxID + \"\\x00\" + doc.Path + \"\\x00\" + doc.HPath))\n\tif task.fingerprint != fingerprint {\n\t\ttask.blockAfter, task.treeAfter = 0, 0\n\t\ttask.fingerprint = fingerprint\n\t}\n\tstart := time.Now()\n\tblockAfter, treeAfter, docDone, busy, err := sql.RefreshHPathsBatch(doc, task.blockAfter, task.treeAfter, task.limit)\n\tif err != nil || busy {\n\t\treturn false, err","sourceCodeStart":456,"sourceCodeEnd":492,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/hpath_refresh.go#L456-L492","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"ok, err := task.refresh(); if err != nil && err.Error() == \"document changed before hpath refresh completed\" { // retrigger the refresh for the document's current hpath }","preventionTips":["Avoid renaming the same document repeatedly in quick succession","Pause sync while performing batch renames via scripts","Serialize rename/move operations on a subtree"],"tags":["concurrency","hpath","race-condition","rename"],"backgroundTag":"invalid-state-transition","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}