siyuan-note/siyuan · error

decode [u] failed

Error message

decode [u] failed: %s

What it means

The `u` query param of the forward-proxy endpoint must be base64 RawURLEncoding of the target URL. If base64 decoding fails (bad characters, wrong alphabet, padding, truncated data) the handler returns "decode [u] failed: <reason>".

Solutions

  1. Encode the target URL with base64.RawURLEncoding (Go) or a URL-safe base64 without padding (JS: btoa output with -/_ and no '=')
  2. URL-encode the resulting string when placing it in the query string
  3. Verify the decoded bytes are the exact URL string before sending (decode round-trip in your client)

Example fix

// before (standard base64 with padding)
const u = btoa("https://example.com"); // aHR0cHM6Ly9leGFtcGxlLmNvbQ==
// after (raw URL-safe base64, no padding)
const u = btoa("https://example.com").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
Defensive patterns

Strategy: validation

Validate before calling

function toBase64Url(s) {
  return btoa(s).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}
const u = toBase64Url(targetUrl);

Type guard

function isValidBase64Url(s) {
  return /^[A-Za-z0-9_-]+$/.test(s);
}

Prevention

When it happens

Trigger: Sending `u` that is not valid RawURLEncoding base64: standard base64 with `+`/`/` or `=` padding, URL-encoding mangled characters, or a truncated value.

Common situations: Using base64.stdEncoding instead of RawURLEncoding in a custom client; double-encoding the value so `%2B` etc. arrive literally; copying a value and dropping trailing characters.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/93bc5949eba9f9b0. Report an issue: GitHub.

Appendix: source

Thrown at kernel/api/network.go:343

	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][]string

View on GitHub (pinned to 9f775e8a12)