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

  1. 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')
  2. Send a syntactically valid JSON object body with Content-Type: application/json
  3. Ensure the body is complete and not truncated (check Content-Length vs actual bytes, disable buffering proxies)
  4. 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

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


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)