siyuan-note/siyuan · error
request paths must not contain query parameters or…
Error message
request paths must not contain query parameters or fragments; encrypted assets are not supported
What it means
This error is thrown by newAssetRelinker when a relink request path contains a URL query string (?...), a fragment (#...), or ForceQuery. The relink engine treats asset paths as plain filesystem paths, and encrypted assets are unsupported, so any request carrying query/fragment syntax is rejected up front before any scanning occurs.
Solutions
- Strip query and fragment components from both OldPath and NewPath before calling RelinkAsset (keep only the path portion of the URL).
- If the value came from an HTTP request, use only the parsed URL's Path field, not the full URL string.
- Verify no template or config concatenates cache-busting or tracking parameters onto asset paths.
- If the source is an encrypted asset, note that relinking of encrypted assets is unsupported; decrypt or move it via the supported encrypted-notebook workflows instead.
- Run relinking in dry-run mode first to validate mappings before a real relink.
Example fix
// before
mappings := []apicontract.AssetRelinkMapping{{OldPath: "assets/foo.png?v=2", NewPath: "assets/bar.png"}}
RelinkAsset(mappings[0].OldPath, mappings[0].NewPath, true)
// after
old := strings.SplitN("assets/foo.png?v=2", "?", 2)[0]
old = strings.SplitN(old, "#", 2)[0]
RelinkAsset(old, "assets/bar.png", true) Defensive patterns
Strategy: validation
Validate before calling
u, _ := url.Parse(p)
if u.RawQuery != "" || u.ForceQuery || u.Fragment != "" || strings.Contains(p, "#") {
return fmt.Errorf("path must not contain query or fragment: %s", p)
} Type guard
func isPlainAssetPath(p string) bool {
u, err := url.Parse(p)
return err == nil && u.RawQuery == "" && !u.ForceQuery && u.Fragment == "" && !strings.Contains(p, "#")
} Prevention
- Always pass only the URL path component, never a full URL
- Strip ? and # segments before building AssetRelinkMapping
- Never copy asset links from rendered HTML with query params
When it happens
Trigger: Calling RelinkAsset / runAssetRelinks / FindAssetReferences via an AssetRelinkMapping whose OldPath or NewPath includes '?', '#', a forced query ('?'), or URL-escaped query/fragment parts; newAssetRelinker parses each raw path with url.Parse and rejects RawQuery, ForceQuery, Fragment, or any literal '#' in the string.
Common situations: Copying an asset URL straight out of a browser or rendered editor (e.g. 'assets/foo.png?opacity=1' or 'assets/foo.png#anchor'); building the mapping from an HTTP request where the full URL was captured instead of the pathname; misconfigured templates that append query parameters for cache busting.
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
- asset must be a regular file
- CalDAV: calendar object path is invalid
- CalDAV: calendar path is invalid
- CardDAV: address book path is invalid
- CardDAV: path is invalid
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/a6ffcf621d603539.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/asset_relink.go:77
matcher *ahocorasick.Matcher
itemByPath map[string]*assetRelinkItem
}
func newAssetRelinker(oldPath, newPath string) (*assetRelinker, error) {
r := &assetRelinker{result: apicontract.AssetReferencesData{
References: []apicontract.AssetReference{}, SkippedNotebooks: []string{},
}}
for i, raw := range []string{oldPath, newPath} {
if i == 1 && raw == "" {
continue
}
p, err := relinkPath(raw)
if err != nil {
return r, err
}
u, _ := url.Parse(raw)
if u.RawQuery != "" || u.ForceQuery || u.Fragment != "" || strings.Contains(raw, "#") {
return r, errors.New("request paths must not contain query parameters or fragments; encrypted assets are not supported")
}
if i == 0 {
r.oldPath = p
} else {
r.newPath = p
}
}
return r, nil
}
func FindAssetReferences(assetPath string) (apicontract.AssetReferencesData, error) {
return runAssetRelink(assetPath, "", true)
}
func RelinkAsset(oldPath, newPath string, dryRun bool) (apicontract.AssetReferencesData, error) {
if newPath == "" {
return apicontract.AssetReferencesData{References: []apicontract.AssetReference{}, SkippedNotebooks: []string{}}, errors.New("newPath is required")
}View on GitHub (pinned to 9f775e8a12)