siyuan-note/siyuan · error
Parses request [ ] failed
Error message
Parses request [%s] failed: %s
What it means
Endpoint.Decode wraps any failure of json.Decoder.Decode when binding a StructJSONBody (or legacy-fields) request body. The wrapped Go JSON error tells you the body is not valid JSON for the declared shape — malformed syntax, wrong top-level type, trailing garbage, or an empty/truncated stream.
Solutions
- Read the wrapped %s detail — it names the exact JSON syntax/offset problem (e.g. 'unexpected end of JSON input', 'cannot unmarshal array into Go value of type map')
- Send a syntactically valid JSON object body with Content-Type: application/json
- Ensure the body is complete and not truncated (check Content-Length vs actual bytes, disable buffering proxies)
- If the endpoint legitimately takes no body, confirm its contract declares NoBody/RawBody/LegacyOptionalBody rather than sending an empty payload
Example fix
// before
fetch("/api/contract/endpoint", {method: "POST", body: "a=1&b=2"}) // not JSON
// after
fetch("/api/contract/endpoint", {method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify({a: 1, b: 2})}) Defensive patterns
Strategy: try-catch
Validate before calling
try { JSON.parse(body); } catch (e) { console.error('client body is not valid JSON', e); } Try / catch
try { await callContractEndpoint(path, body) } catch (e) { if (String(e).includes('Parses request')) { console.error(`invalid JSON body for ${path}:`, e.message); } throw e; } Prevention
- Always send JSON.stringify'd object bodies with Content-Type: application/json
- Never send form-encoded or empty bodies to StructJSONBody/LegacyBody endpoints
- Parse the wrapped detail (%s) to locate the exact JSON error offset
- Check for truncation when bodies pass through proxies
When it happens
Trigger: POSTing to a contract endpoint with a body that fails json.Decode: invalid JSON syntax, a JSON array/string/number where a JSON object is required (legacy fields mode), an empty request body on a required-body endpoint, or a truncated body.
Common situations: Sending form-encoded or multipart data instead of JSON; forgetting Content-Type plus a raw body; clients sending JSON with BOM or trailing commas; empty POST bodies where the contract requires LegacyBody (not LegacyOptionalBody); proxy truncating large bodies.
Related errors
- createEmptyParagraph must be a boolean
- Field [ ] has an invalid type
- Field [ ] must not be null
- map[string]json.RawMessage
- Parses request [ ] failed
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/189687d54439a2e5.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/apicontract/decode.go:27
"reflect"
"strings"
)
// Decode 按精确的 JSON 字段名绑定请求,缺失、null 和兼容转换由字段声明控制。
func (e Endpoint[Request, Data]) Decode(reader io.Reader) (request Request, err error) {
if e.definition.Body == NoBody || e.definition.Body == RawBody {
return
}
if reader == nil {
reader = bytes.NewReader(nil)
}
if e.decodeRequest != nil {
return e.decodeRequest(reader)
}
if e.definition.Body == StructJSONBody {
err = json.NewDecoder(reader).Decode(&request)
if err != nil {
err = fmt.Errorf("Parses request [%s] failed: %s", e.definition.Path, err)
}
return
}
var fields map[string]json.RawMessage
err = json.NewDecoder(reader).Decode(&fields)
if err != nil {
if e.definition.Body == LegacyOptionalBody {
return request, nil
}
if errors.Is(err, io.EOF) {
err = errors.New("the request body is empty or truncated (EOF)")
}
return request, fmt.Errorf("Parses request [%s] failed: %s", e.definition.Path, err)
}
value := reflect.ValueOf(&request).Elem()
if value.Kind() != reflect.Struct {
return request, fmt.Errorf("request contract must be a struct")
}View on GitHub (pinned to 9f775e8a12)