{"record":{"id":"bbfa86966202c9ad","repo":"siyuan-note/siyuan","slug":"parse-u-failed-s","errorCode":null,"errorMessage":"parse [u] failed: %s","messagePattern":"parse \\[u\\] failed: (.+?)","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"kernel/api/network.go","lineNumber":361,"sourceCode":"//\n// Query params:\n//   - `u`: RawURLEncoding base64 of the target URL string.\n//   - `h`: RawURLEncoding base64 of a JSON object map[string][]string.\n//   - `timeout`: The timeout for the request in nanoseconds.\nfunc parseForwardProxyParams(c *gin.Context) (parsedURL *url.URL, headers *http.Header, timeout time.Duration, err error) {\n\tuParam := c.Query(\"u\")\n\tif uParam == \"\" {\n\t\terr = fmt.Errorf(\"missing query param [u]\")\n\t\treturn\n\t}\n\tuBytes, decErr := base64.RawURLEncoding.DecodeString(uParam)\n\tif decErr != nil {\n\t\terr = fmt.Errorf(\"decode [u] failed: %s\", decErr.Error())\n\t\treturn\n\t}\n\tparsedURL, err = url.ParseRequestURI(string(uBytes))\n\tif err != nil {\n\t\terr = fmt.Errorf(\"parse [u] failed: %s\", err.Error())\n\t\treturn\n\t}\n\n\th := http.Header{}\n\theaders = &h\n\thParam := c.Query(\"h\")\n\tif hParam != \"\" {\n\t\thBytes, decErr := base64.RawURLEncoding.DecodeString(hParam)\n\t\tif decErr != nil {\n\t\t\terr = fmt.Errorf(\"decode [h] failed: %s\", decErr.Error())\n\t\t\treturn\n\t\t}\n\t\tvar record map[string][]string\n\t\tif jsonErr := json.Unmarshal(hBytes, &record); jsonErr != nil {\n\t\t\terr = fmt.Errorf(\"parse [h] failed: %s\", jsonErr.Error())\n\t\t\treturn\n\t\t}\n","sourceCodeStart":343,"sourceCodeEnd":379,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/api/network.go#L343-L379","documentation":"Returned by parseForwardProxyParams (network.go:361) when the `u` parameter decoded from base64 is not a parseable request URI. After successful base64 decode, url.ParseRequestURI(string(uBytes)) at network.go:359 fails — typically because the decoded string is a relative path, malformed, or missing the scheme/host. The request is rejected with HTTP 400.","triggerScenarios":"Decoded `u` is something like '/path/to/thing' (no scheme/host), 'example.com' (no scheme), contains illegal characters/spaces, or is a fragment-only/empty string. ParseRequestURI is stricter than Parse and demands an absolute request-URI form.","commonSituations":"Client decoded a relative URL. Whitespace accidentally included in the base64 source. Target URL built by string concatenation that dropped the scheme. Unicode/IRI that was not percent-encoded before base64.","solutions":["Ensure the target URL is absolute with scheme and host: 'https://host/path' (HTTP) or 'wss://host/path' (WS).","Trim whitespace/newlines from the URL string before base64-encoding.","Percent-encode any non-ASCII components of the URL prior to encoding."],"exampleFix":"// before\nconst u = encode('example.com/api') // no scheme\n// after\nconst u = encode('https://example.com/api')","handlingStrategy":"validation","validationCode":"// Require an absolute URL with scheme+host\nfunction validTarget(u) { try { const p = new URL(u); return ['http:','https:','ws:','wss:'].includes(p.protocol) && !!p.host; } catch { return false; } }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate the target is an absolute http(s)/ws(s) URL with a host before encoding.","Trim whitespace/newlines from the URL prior to base64.","Percent-encode non-ASCII URL components before encoding."],"tags":["network","proxy","validation","url","kernel"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}