siyuan-note/siyuan · error
decode [u] failed: %s
Error message
decode [u] failed: %s
What it means
Returned by parseForwardProxyParams (network.go:356) when the `u` query parameter is present but cannot be base64-decoded with RawURLEncoding. The decoder expects URL-safe base64 with no padding; standard base64, padded base64, hex, or raw text all fail decoding and the request is rejected with HTTP 400.
Source
Thrown at kernel/api/network.go:356
client.SetRedirectPolicy(req.MaxRedirectPolicy(3))
return client
}
// parseForwardProxyParams decodes the `u` and `h` query parameters.
//
// Query params:
// - `u`: RawURLEncoding base64 of the target URL string.
// - `h`: RawURLEncoding base64 of a JSON object map[string][]string.
// - `timeout`: The timeout for the request in nanoseconds.
func parseForwardProxyParams(c *gin.Context) (parsedURL *url.URL, headers *http.Header, timeout time.Duration, err error) {
uParam := c.Query("u")
if uParam == "" {
err = fmt.Errorf("missing query param [u]")
return
}
uBytes, decErr := base64.RawURLEncoding.DecodeString(uParam)
if decErr != nil {
err = fmt.Errorf("decode [u] failed: %s", decErr.Error())
return
}
parsedURL, err = url.ParseRequestURI(string(uBytes))
if err != nil {
err = fmt.Errorf("parse [u] failed: %s", err.Error())
return
}
h := http.Header{}
headers = &h
hParam := c.Query("h")
if hParam != "" {
hBytes, decErr := base64.RawURLEncoding.DecodeString(hParam)
if decErr != nil {
err = fmt.Errorf("decode [h] failed: %s", decErr.Error())
return
}
var record map[string][]stringView on GitHub (pinned to 251596fc0d)
Solutions
- Encode the target URL with base64 RawURLEncoding (URL-safe alphabet, no padding): Go base64.RawURLEncoding.EncodeToString, or JS btoa then replace +->-, /->_, strip trailing '='.
- Do NOT URL-encode the base64 string a second time; ensure it is placed raw in the query.
- Verify the decoded output is a valid absolute http/https/ws/wss URL before sending.
Example fix
// before const u = btoa(targetUrl) // standard base64, fails RawURL decoding // after const u = btoa(targetUrl).replace(/\+/g,'-').replace(/\//g,'_').replace(/=+$/,'')
Defensive patterns
Strategy: validation
Validate before calling
function base64UrlSafe(s) {
return btoa(s).replace(/\+/g,'-').replace(/\//g,'_').replace(/=+$/,'');
} Prevention
- Use one shared URL-safe-base64 helper for all `u`/`h` params.
- Never URL-encode the base64 string a second time.
- Strip all padding '=' characters.
When it happens
Trigger: Sending ?u=<standard-base64> (with '+'/'/'/'=' instead of '-'/['_']), ?u=<plaintext-url>, ?u=<hex>, or a corrupted/truncated encoding. base64.RawURLEncoding.DecodeString at network.go:354 returns an error and it is wrapped at line 356; httpProxy/wsProxy respond HTTP 400.
Common situations: Client used btoa() (standard base64) instead of URL-safe encoding. Padding '=' characters were not stripped. The URL was URL-encoded again, mangling the base64 alphabet. Copy-paste introduced whitespace or newlines.
Related errors
- decode [h] failed: %s
- missing query param [u]
- parse [u] failed: %s
- parse [h] failed: %s
- parse [t] failed: %s
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/93bc5949eba9f9b0.
Report an issue: GitHub.