siyuan-note/siyuan · error

load block tree [%s] failed: %w

Error message

load block tree [%s] failed: %w

What it means

Returned by buildBlockUpdateOperations when loadTree(input.ID) returns a non-nil error. The cache lookup (resolveTree + treeCache) missed, so the loader was invoked; the loader failed for some underlying reason which is wrapped with %w. The ID itself passed IsNodeIDPattern - this is a storage/IO failure.

Source

Thrown at kernel/model/block_update.go:113

		data, dataTree, parseErr := parseBlockUpdateData(input.Data, input.DataType, luteEngine)
		if parseErr != nil {
			return nil, nil, parseErr
		}

		var oldTree *parse.Tree
		var cacheKey blockUpdateTreeKey
		hasCacheKey := false
		if blockTree := resolveTree(input.ID); nil != blockTree {
			cacheKey = blockUpdateTreeKey{boxID: blockTree.BoxID, rootID: blockTree.RootID}
			hasCacheKey = true
			oldTree = treeCache[cacheKey]
		}
		if nil == oldTree {
			var loadErr error
			oldTree, loadErr = loadTree(input.ID)
			if loadErr != nil {
				return nil, nil, fmt.Errorf("load block tree [%s] failed: %w", input.ID, loadErr)
			}
			if nil == oldTree || nil == oldTree.Root {
				return nil, nil, fmt.Errorf("load block tree [%s] failed: tree is empty", input.ID)
			}
			treeCache[blockUpdateTreeKey{boxID: oldTree.Box, rootID: oldTree.ID}] = oldTree
			if hasCacheKey {
				treeCache[cacheKey] = oldTree
			}
		}
		oldNode := treenode.GetNodeInTree(oldTree, input.ID)
		if nil == oldNode {
			return nil, nil, fmt.Errorf("block [%s] not found", input.ID)
		}

		if _, ok := rootIDSet[oldTree.ID]; !ok {
			rootIDSet[oldTree.ID] = struct{}{}
			rootIDs = append(rootIDs, oldTree.ID)
		}

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Inspect the wrapped error (errors.Unwrap or %w chain) for the OS-level cause.
  2. Verify the .sy file exists at the expected path under data/<box>/<path>.sy.
  3. Restore from history/snapshot if the file is corrupted.
  4. Rebuild the index after restoring the file.
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := os.Stat(expectedSyPath(id)); err != nil {
    return fmt.Errorf("sy file missing for %s", id)
}

Try / catch

ops, roots, err := buildBlockUpdateOperations(inputs, resolver, loader)
if err != nil {
    if cause := errors.Unwrap(err); cause != nil {
        log.Warnf("load failed: %v", cause)
    }
    // fall back: rebuild index, then retry once
}

Prevention

When it happens

Trigger: Missing .sy file for the block's root; corrupted .sy file that fails to unmarshal; filelock contention; disk/permission error; network share hiccup.

Common situations: Out-of-band deletion of the .sy file; partial sync that left an incomplete file; mobile storage permission revoked mid-operation.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/3bcf78442e3f79f8. Report an issue: GitHub.