{"record":{"id":"af9a3a77e8f3f67d","repo":"siyuan-note/siyuan","slug":"parse-h-failed-s","errorCode":null,"errorMessage":"parse [h] failed: %s","messagePattern":"parse \\[h\\] failed: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/api/network.go","lineNumber":363,"sourceCode":"\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\n\t\tfor k, vs := range record {\n\t\t\tfor _, v := range vs {\n\t\t\t\th.Add(k, v)\n\t\t\t}\n\t\t}\n\t}\n\n\ttimeout = 30 * time.Second\n\ttParam := c.Query(\"t\")\n\tif tParam != \"\" {\n\t\tif t, parseErr := time.ParseDuration(tParam); parseErr != nil {\n\t\t\terr = fmt.Errorf(\"parse [t] failed: %s\", parseErr.Error())\n\t\t\treturn\n\t\t} else {\n\t\t\ttimeout = t","sourceCodeStart":345,"sourceCodeEnd":381,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/api/network.go#L345-L381","documentation":"Error from parseForwardProxyParams in the network forward-proxy endpoint: the base64url-decoded [h] query parameter cannot be unmarshaled into a map[string][]string HTTP header record, so the client sent a malformed header encoding for the proxied request.","triggerScenarios":"`h` decodes to text that is not JSON (plain text, single-quoted JSON, a flat map[string]string instead of map[string][]string).","commonSituations":"Clients serializing headers as {\"X-Token\":\"abc\"} instead of {\"X-Token\":[\"abc\"]}; string-concatenated pseudo-JSON; forgetting JSON.stringify before base64-encoding.","solutions":["Serialize headers as a JSON object whose values are string arrays: {\"Header\": [\"value\"]}","Run the object through JSON.stringify (or json.Marshal) before base64-encoding","Validate the JSON parses into map[string][]string in your client before sending"],"exampleFix":"// before\nJSON.stringify({\"X-Token\": \"abc\"}) // wrong shape, values must be arrays\n// after\nJSON.stringify({\"X-Token\": [\"abc\"]})","handlingStrategy":"validation","validationCode":"const record = {};\nfor (const [k, v] of Object.entries(headers)) {\n  record[k] = Array.isArray(v) ? v : [v];\n}\nconst h = toBase64Url(JSON.stringify(record));","typeGuard":"function isHeaderRecord(o) {\n  return typeof o === \"object\" && o !== null && Object.values(o).every(v => Array.isArray(v) && v.every(x => typeof x === \"string\"));\n}","tryCatchPattern":null,"preventionTips":["Normalize header values to string arrays before serializing","Always JSON.stringify before base64-encoding, never encode raw text"],"tags":["json","headers","proxy","validation"],"backgroundTag":"json-unmarshal-failed","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"}