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

  1. Strip query and fragment components from both OldPath and NewPath before calling RelinkAsset (keep only the path portion of the URL).
  2. If the value came from an HTTP request, use only the parsed URL's Path field, not the full URL string.
  3. Verify no template or config concatenates cache-busting or tracking parameters onto asset paths.
  4. 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.
  5. 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

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


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)