siyuan-note/siyuan · warning
invalid asset path
Error message
invalid asset path: %q
What it means
relinkPath parses an asset URL reference before matching it to a file on disk. The first guard rejects values that fail url.Parse, are absolute URLs, or carry a host or opaque part — such references are not local workspace assets and cannot be relinked.
Solutions
- Replace external URL references in the document with locally imported assets (assets/... paths)
- Skip or preprocess non-local references before invoking the relinker
- If the URL should be local, remove the scheme/host portion and ensure the value is a relative assets/ path
Example fix
// before
relink("https://example.com/img.png")
// after
relink("assets/img-20240101120000-ab12cd3.png") Defensive patterns
Strategy: validation
Validate before calling
u, err := url.Parse(v)
if err != nil || u.IsAbs() || u.Host != "" || u.Opaque != "" { /* not a local asset reference */ } Type guard
func isRelativeAssetRef(v string) bool { u, err := url.Parse(v); return err == nil && !u.IsAbs() && u.Host == "" && u.Opaque == "" } Try / catch
if _, err := relinkPath(v); err != nil { log.Warnf("skipping non-local ref %s: %v", v, err); return "" } Prevention
- Import external images into assets/ instead of linking absolute URLs
- Sanitize pasted/clipped content before storing asset references
- Filter document asset references to relative paths before batch relinking
When it happens
Trigger: Calling newAssetRelinker, reference, or list with an asset value like "https://example.com/img.png", "mailto:a@b", or a malformed value that url.Parse rejects.
Common situations: Documents containing external network images or protocol links pasted as asset references; clippings that stored absolute URLs; data migrated from other tools that use full URLs.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- assetPath is not an image referenced by the document
- only global assets/... images are supported
- only local assets/... images are supported
- parse [u] failed
- accessing assets in encrypted notebook
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/ab900c3d1d716c24.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/asset_relink_references.go:40
xhtml "golang.org/x/net/html"
)
type assetRelinker struct {
oldPath string
newPath string
result apicontract.AssetReferencesData
routes map[string]*assetRelinker
collectOnly bool
recordless bool
disabled bool
changes int
}
// relinkPath 按 URL 路径解码一次,查询参数和片段不参与资源文件名匹配。
func relinkPath(value string) (string, error) {
u, err := url.Parse(value)
if err != nil || u.IsAbs() || u.Host != "" || u.Opaque != "" {
return "", fmt.Errorf("invalid asset path: %q", value)
}
p := strings.TrimPrefix(u.Path, "/")
if !strings.HasPrefix(p, "assets/") || path.Clean(p) != p || strings.ContainsAny(p, "\\\x00\r\n") || strings.HasSuffix(p, "/") {
return "", fmt.Errorf("invalid asset path: %q", value)
}
for _, segment := range strings.Split(p, "/") {
if strings.Contains(segment, ":") {
return "", fmt.Errorf("invalid asset path: %q", value)
}
}
return p, nil
}
func (r *assetRelinker) reference(raw, kind string, location apicontract.AssetReference) string {
link, annotationID := raw, ""
if kind == "annotation" {
link, annotationID = util.SplitFileAnnotationRef(raw)
if link == "" {View on GitHub (pinned to 9f775e8a12)