siyuan-note/siyuan · error

Conf.Language(12) (localized asset-not-found message)

Error message

Conf.Language(12) (localized asset-not-found message)

What it means

This is the terminal failure of GetAssetAbsPathInBox: after the box-local lookup, the deferred global data/assets fallback, and the non-encrypted-box fallback all fail to find the file, it returns the localized 'asset not found' message (Conf.Language(12)) interpolated with the relative path. It means the path was valid but no such asset exists in any searchable location.

Source

Thrown at kernel/model/assets.go:1261

			// 验证解析后的路径仍在 <boxID>/assets/ 或全局 data/assets/ 下
			expectedPrefix := filepath.Join(util.DataDir, "assets")
			if boxID != "" {
				expectedPrefix = filepath.Join(util.DataDir, boxID, "assets")
			}
			if !gulu.File.IsSubPath(expectedPrefix, realP) {
				return "", fmt.Errorf("symlink [%s] resolves outside assets directory: [%s]", p, realP)
			}
		}
		return p, nil
	}
	// 非加密 box 的资源可能回退到全局 data/assets(兼容旧笔记本结构)
	if deferredPath, deferredErr := deferredAssetPath(relativePath, boxID, true); deferredErr != nil || deferredPath != "" {
		return deferredPath, deferredErr
	}
	if !IsEncryptedBox(boxID) {
		return GetAssetAbsPathWithOpt(relativePath, false)
	}
	return "", fmt.Errorf(Conf.Language(12), relativePath)
}

// GetAssetAbsPathWithOpt 与 GetAssetAbsPath 一致,但可通过 includeEncrypted 控制是否遍历加密 box。
// serveAssets 传 true(下游 serveEncryptedAsset 会按锁定状态 fail-closed),其他调用方传 false(安全跳过)。
func GetAssetAbsPathWithOpt(relativePath string, includeEncrypted bool) (string, error) {
	relativePath = strings.TrimSpace(relativePath)
	if idx := strings.Index(relativePath, "?"); idx >= 0 {
		relativePath = relativePath[:idx]
	}

	absPath, err := getAssetAbsPath(relativePath, includeEncrypted)
	if err == nil && absPath != "" {
		return absPath, nil
	}

	if err != nil {
		return "", err
	}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Verify the file exists on disk under <box>/assets/ or data/assets/ with the exact filename
  2. Re-upload/copy the missing asset and update the document reference to the new path
  3. If the asset is in an encrypted box, ensure the box is unlocked so the lookup path can access it
  4. Check sync history or file history (data/history) to recover the deleted asset

Example fix

// before
GetAssetAbsPathInBox("assets/old-name.png", boxID) // deleted
// after
GetAssetAbsPathInBox("assets/renamed-copy.png", boxID) // existing asset
Defensive patterns

Strategy: try-catch

Validate before calling

// check existence before resolving
const { data } = await fetchPost("/api/filetree/getDoc", { id: blockID });
// or: verify the file exists via /api/file/getFile path listing

Try / catch

p, err := GetAssetAbsPathInBox(rel, boxID)
if err != nil {
  // localized not-found: notify user, offer history recovery
  util.PushMsg(fmt.Sprintf("asset missing: %s", rel), 3000)
  return
}

Prevention

When it happens

Trigger: Requesting an asset path that does not exist under <box>/assets/, data/assets/, or any non-encrypted box; requesting assets of encrypted notebooks through the non-privileged path; a typo'd or renamed asset filename; assets lost by sync or deletion.

Common situations: Document references an asset that was deleted or renamed; sync conflicts dropped the file; caller asks for an asset belonging to an encrypted box without the unlocked context; mobile/older clients referencing assets with stale paths.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/f58e43878a27af63. Report an issue: GitHub.