siyuan-note/siyuan · error

walk global assets [%s] failed: %w

Error message

walk global assets [%s] failed: %w

What it means

The kernel failed while walking the global data/assets directory to build a map of asset paths (used by asset cleanup/refresh operations such as RemoveUnusedAssets). filepath.Walk returned a non-nil, non-not-exist error (e.g. permission denied on a subdirectory or I/O error on an entry), which is wrapped with the assets directory path for context. If the directory simply does not exist the walk is treated as a no-op, so this error means a real filesystem failure occurred during traversal.

Source

Thrown at kernel/model/assets.go:2815

		}

		if filelock.IsHidden(assetPath) {
			// 清理资源文件时忽略隐藏文件 Ignore hidden files when cleaning unused assets https://github.com/siyuan-note/siyuan/issues/12172
			return nil
		}

		relPath, relErr := assetPathMapKey(dataAssetsAbsPath, assetPath, d.IsDir())
		if relErr != nil {
			return relErr
		}
		assetsAbsPathMap[relPath] = assetPath
		return nil
	})
	if walkErr != nil {
		if os.IsNotExist(walkErr) {
			return
		}
		return nil, fmt.Errorf("walk global assets [%s] failed: %w", dataAssetsAbsPath, walkErr)
	}
	return
}

func assetPathMapKey(assetsDirPath, assetPath string, isDir bool) (ret string, err error) {
	relPath, err := filepath.Rel(assetsDirPath, assetPath)
	if err != nil {
		return
	}
	relPath = filepath.ToSlash(relPath)
	if relPath == "." || relPath == ".." || strings.HasPrefix(relPath, "../") || path.IsAbs(relPath) {
		err = fmt.Errorf("asset path [%s] is outside assets directory [%s]", assetPath, assetsDirPath)
		return
	}

	ret = path.Join("assets", relPath)
	if isDir {
		ret += "/"

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Check permissions on data/assets and its children (chmod/chown so the kernel user can read everything).
  2. Run with the message's wrapped cause: the %w suffix names the underlying walk error (e.g. 'permission denied' on a specific path) and fix that path.
  3. Exclude or remove broken entries (dead symlinks, locked files) under data/assets.
  4. If the directory is intentionally absent, no action is needed — a missing data/assets is silently tolerated; only fix cases where it exists but is unreadable.

Example fix

// before (server container): data/assets owned by root, kernel runs as siyuan
// walk global assets [/siyuan/data/assets] failed: open /siyuan/data/assets/sub: permission denied
// after: fix ownership/permissions on the host or in the container image
chown -R siyuan:siyuan /siyuan/data/assets
chmod -R u+rX /siyuan/data/assets
Defensive patterns

Strategy: try-catch

Validate before calling

const fs = require('fs');
function assertAssetsReadable(dir) {
  if (!fs.existsSync(dir)) return; // missing dir is tolerated by the kernel
  fs.accessSync(dir, fs.constants.R_OK | fs.constants.X_OK);
  for (const e of fs.readdirSync(dir)) fs.accessSync(path.join(dir, e), fs.constants.R_OK);
}

Try / catch

try {
  await api.removeUnusedAssets();
} catch (e) {
  if (/walk global assets .* failed/.test(e.message)) {
    console.error("Check permissions/locks under data/assets:", e.cause ?? e.message);
  }
}

Prevention

When it happens

Trigger: Calling asset cleanup paths (e.g. the API that removes unused assets) when a file or subdirectory under data/assets cannot be read: unreadable directory permissions, symlink loops, I/O errors, or a race where a file is removed mid-walk.

Common situations: Running the kernel in a container where data/assets was mounted with restrictive permissions; an antivirus or backup tool locking files on Windows; a partially-synced cloud-drive folder producing broken entries under data/assets.

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/daf0cc9c3eeedd2a. Report an issue: GitHub.