siyuan-note/siyuan · error
box mismatch: caller specified
Error message
box mismatch: caller specified [%s] but URL has [%s]
What it means
assetPathAndBox parses an optional ?box=<id> query parameter from an asset path and reconciles it with the boxID the caller passed explicitly. When the caller supplied a non-empty boxID that differs from the box ID in the URL query, this error is returned to avoid silently resolving the asset from the wrong notebook.
Solutions
- Make the box IDs consistent: either drop the caller-provided boxID (pass "") and let the URL's ?box= parameter win, or strip the ?box= query from the path before calling
- Update the stored asset link so its ?box= parameter matches the notebook it lives in
- If the asset truly belongs to another notebook, call the resolver with that notebook's boxID and no conflicting query parameter
Example fix
// before: conflict between caller box and URL query
model.GetAssetAbsPathInBox("assets/img.png?box=20240101111111-aaaa", "20250101111222-bbbb")
// after: strip the query or align the box
model.GetAssetAbsPathInBox("assets/img.png", "20250101111222-bbbb") Defensive patterns
Strategy: validation
Validate before calling
u, _ := url.Parse(assetRef)
qBox := u.Query().Get("box")
if qBox != "" && callerBoxID != "" && qBox != callerBoxID {
// reconcile before calling: pass one source of truth only
} Try / catch
abs, err := model.GetAssetAbsPathInBox(ref, boxID)
if err != nil && strings.Contains(err.Error(), "box mismatch") {
// strip the query and retry with the caller's box
clean := strings.SplitN(ref, "?", 2)[0]
abs, err = model.GetAssetAbsPathInBox(clean, boxID)
} Prevention
- Choose one source of truth for the box: either encode it in the URL or pass it as an argument, not both
- When copying asset links between notebooks, rewrite the ?box= parameter
- Store raw asset paths without query strings in your own persistence layers
When it happens
Trigger: Calling GetAssetAbsPathInBox (or functions routed through assetPathAndBox such as assetReferenceExists, AcquireExportArtifactLease, GetMobileExportName) with e.g. path="assets/img.png?box=20240101111111-aaaa" while also passing boxID="20250101111222-bbbb".
Common situations: Copying an asset URL (which embeds its source box) from one document into code that resolves it within a different notebook's context; export code passing the current box while the stored link was created in another notebook; stale hard-coded URLs after merging notebooks.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/9ab49abfc0b9ff62.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/assets.go:1202
func IsHTMLAssetIFrameSrc(assetPath string) bool {
parsed, err := url.Parse(assetPath)
if err != nil || !strings.EqualFold(parsed.Query().Get("iframe"), "true") {
return false
}
return IsLocalHTMLAssetPath(assetPath)
}
func assetPathAndBox(relativePath, defaultBoxID string) (cleanPath, boxID string, err error) {
relativePath = strings.TrimSpace(relativePath)
boxID = defaultBoxID
if idx := strings.Index(relativePath, "?"); idx >= 0 {
query := relativePath[idx+1:]
relativePath = relativePath[:idx]
if values, parseErr := url.ParseQuery(query); parseErr == nil {
if queryBoxID := strings.TrimSpace(values.Get("box")); queryBoxID != "" {
if defaultBoxID != "" && defaultBoxID != queryBoxID {
// 调用方指定了 boxID 但 URL 里是另一个 box:拒绝,防止解析到错误 box
err = fmt.Errorf("box mismatch: caller specified [%s] but URL has [%s]", defaultBoxID, queryBoxID)
return
}
boxID = queryBoxID
}
}
}
cleanPath = filepath.ToSlash(relativePath)
return
}
// GetAssetAbsPathInBox 在指定 box 内解析资源绝对路径,不进行全局遍历。
// relativePath 必须以 assets/ 前缀开头,boxID 为空且路径没有 box 查询参数时只解析普通/全局资源,不遍历加密 box。
// 加密 box 直接从 <boxID>/assets/ 查找,不依赖后缀匹配。
func GetAssetAbsPathInBox(relativePath, boxID string) (string, error) {
var err error
relativePath, boxID, err = assetPathAndBox(relativePath, boxID)
if err != nil {
return "", errView on GitHub (pinned to 9f775e8a12)