{"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":400,"severity":"error","filePath":"kernel/api/network.go","lineNumber":376,"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":358,"sourceCodeEnd":394,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/api/network.go#L358-L394","documentation":"Returned by parseForwardProxyParams (network.go:376) when the `h` parameter decodes from base64 but is not valid JSON of the expected shape map[string][]string. After base64 decode, json.Unmarshal at network.go:375 fails — common causes are non-JSON text, a JSON object whose values are not arrays of strings (e.g. {\"k\":\"v\"} instead of {\"k\":[\"v\"]}), or truncated JSON.","triggerScenarios":"Sending ?h=<base64-of-non-JSON> or ?h=<base64-of-{\"k\":\"v\"}> (string value instead of array). Trailing garbage after a valid JSON object. BOM or whitespace issues. The shape mismatch trips json.Unmarshal into map[string][]string at line 374.","commonSituations":"Client built the header map as {Header: 'value'} instead of {Header: ['value']}. JSON produced by a serializer that emits single strings for single-element headers. Encoding/charset mismatch inserted a BOM.","solutions":["Structure header values as arrays of strings: {\"X-Key\":[\"v1\",\"v2\"], \"Authorization\":[\"Bearer x\"]}.","Validate the JSON parses and matches map[string][]string before base64-encoding.","Strip BOM/leading whitespace; ensure the JSON is a single top-level object."],"exampleFix":"// before\nconst h = enc(JSON.stringify({ 'X-Key': 'v' })) // value not an array\n// after\nconst h = enc(JSON.stringify({ 'X-Key': ['v'] }))","handlingStrategy":"type-guard","validationCode":"// Ensure header map values are arrays of strings\nfunction isHeaderMap(h) {\n  return typeof h === 'object' && h !== null && Object.values(h).every(v => Array.isArray(v) && v.every(x => typeof x === 'string'));\n}","typeGuard":"function isHeaderMap(h: unknown): h is Record<string, string[]> {\n  if (typeof h !== 'object' || h === null) return false;\n  return Object.values(h).every(v => Array.isArray(v) && v.every(x => typeof x === 'string'));\n}","tryCatchPattern":null,"preventionTips":["Always shape header values as string arrays, even for single values.","Validate the parsed JSON matches map[string][]string before encoding.","Strip BOM and ensure the JSON is a single object."],"tags":["network","proxy","validation","json","kernel"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}