{"record":{"id":"a6ffcf621d603539","repo":"siyuan-note/siyuan","slug":"request-paths-must-not-contain-query-parameters-or-fragments","errorCode":null,"errorMessage":"request paths must not contain query parameters or fragments; encrypted assets are not supported","messagePattern":"request paths must not contain query parameters or fragments; encrypted assets are not supported","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/asset_relink.go","lineNumber":77,"sourceCode":"\tmatcher         *ahocorasick.Matcher\n\titemByPath      map[string]*assetRelinkItem\n}\n\nfunc newAssetRelinker(oldPath, newPath string) (*assetRelinker, error) {\n\tr := &assetRelinker{result: apicontract.AssetReferencesData{\n\t\tReferences: []apicontract.AssetReference{}, SkippedNotebooks: []string{},\n\t}}\n\tfor i, raw := range []string{oldPath, newPath} {\n\t\tif i == 1 && raw == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tp, err := relinkPath(raw)\n\t\tif err != nil {\n\t\t\treturn r, err\n\t\t}\n\t\tu, _ := url.Parse(raw)\n\t\tif u.RawQuery != \"\" || u.ForceQuery || u.Fragment != \"\" || strings.Contains(raw, \"#\") {\n\t\t\treturn r, errors.New(\"request paths must not contain query parameters or fragments; encrypted assets are not supported\")\n\t\t}\n\t\tif i == 0 {\n\t\t\tr.oldPath = p\n\t\t} else {\n\t\t\tr.newPath = p\n\t\t}\n\t}\n\treturn r, nil\n}\n\nfunc FindAssetReferences(assetPath string) (apicontract.AssetReferencesData, error) {\n\treturn runAssetRelink(assetPath, \"\", true)\n}\n\nfunc RelinkAsset(oldPath, newPath string, dryRun bool) (apicontract.AssetReferencesData, error) {\n\tif newPath == \"\" {\n\t\treturn apicontract.AssetReferencesData{References: []apicontract.AssetReference{}, SkippedNotebooks: []string{}}, errors.New(\"newPath is required\")\n\t}","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/asset_relink.go#L59-L95","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nmappings := []apicontract.AssetRelinkMapping{{OldPath: \"assets/foo.png?v=2\", NewPath: \"assets/bar.png\"}}\nRelinkAsset(mappings[0].OldPath, mappings[0].NewPath, true)\n// after\nold := strings.SplitN(\"assets/foo.png?v=2\", \"?\", 2)[0]\nold = strings.SplitN(old, \"#\", 2)[0]\nRelinkAsset(old, \"assets/bar.png\", true)","handlingStrategy":"validation","validationCode":"u, _ := url.Parse(p)\nif u.RawQuery != \"\" || u.ForceQuery || u.Fragment != \"\" || strings.Contains(p, \"#\") {\n    return fmt.Errorf(\"path must not contain query or fragment: %s\", p)\n}","typeGuard":"func isPlainAssetPath(p string) bool {\n    u, err := url.Parse(p)\n    return err == nil && u.RawQuery == \"\" && !u.ForceQuery && u.Fragment == \"\" && !strings.Contains(p, \"#\")\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["validation","asset-relink","url"],"backgroundTag":"invalid-url-format","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}