siyuan-note/siyuan · error

Parses request [ ] failed

Error message

Parses request [%s] failed: %s

What it means

This is the generic wrapper message from syncRequestFields for all /api/sync/* contract endpoints: 'Parses request [<path>] failed: <detail>'. Any JSON syntax error or type failure while reading the top-level request object ends up here; EOF is first rewritten to 'the request body is empty or truncated (EOF)' and map[string]json.RawMessage is normalized to map[string]interface {} in the detail.

Solutions

  1. Read the detail after 'failed: ' — it names the exact JSON problem
  2. Validate the JSON with a parser/linter before sending
  3. Ensure the top level is a JSON object containing the endpoint's expected fields (enabled, interval, mode, provider, name, etc.)

Example fix

// before
{"enabled": true,}   // trailing comma -> parse error
// after
{"enabled": true}
Defensive patterns

Strategy: validation

Validate before calling

try { JSON.stringify(payload); } catch (e) { throw new Error('payload is not valid JSON: ' + e.message); }

Type guard

const isObject = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);

Try / catch

const res = await fetchPost(path, payload); if (res.code !== 0 && res.msg.startsWith('Parses request')) { console.error('payload rejected:', res.msg); }

Prevention

When it happens

Trigger: Malformed JSON such as {enabled:} or trailing commas; top-level payload being an array or string instead of an object; wrong Content-Type causing the raw body to be misread; duplicate fields or invalid numeric literals rejected by the legacy parser.

Common situations: Hand-written payloads with unquoted keys; clients sending form-encoded data to a JSON endpoint; template engines interpolating invalid JSON; version mismatch where an old field format no longer parses.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


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

Appendix: source

Thrown at kernel/apicontract/sync.go:154

		return nil
	}
	detail := strings.ReplaceAll(err.Error(), "apicontract.Sync"+name, "conf."+name)
	return errors.New(strings.ReplaceAll(detail, "struct field Sync"+name+".", "struct field "+name+"."))
}

// syncRequestFields 保留整份请求的 JSON 数字解析、重复字段和首个对象读取语义。
func syncRequestFields(reader io.Reader, path string) (fields map[string]json.RawMessage, err error) {
	var raw json.RawMessage
	err = json.NewDecoder(reader).Decode(&raw)
	if err == nil {
		fields, err = legacyJSONValue[map[string]json.RawMessage](raw)
	}
	if err != nil {
		if errors.Is(err, io.EOF) {
			err = errors.New("the request body is empty or truncated (EOF)")
		}
		detail := strings.ReplaceAll(err.Error(), "map[string]json.RawMessage", "map[string]interface {}")
		err = fmt.Errorf("Parses request [%s] failed: %s", path, detail)
	}
	return
}

func init() {
	for _, endpoint := range []*Endpoint[SyncEnabledRequest, Null]{&SetSyncEnable, &SetSyncPerception, &SetSyncGenerateConflictDoc} {
		path := endpoint.definition.Path
		endpoint.decodeRequest = func(reader io.Reader) (r SyncEnabledRequest, err error) {
			fields, err := syncRequestFields(reader, path)
			if err == nil {
				r.Enabled, err = legacyField[bool](fields, "enabled", "Boolean", true)
			}
			return r, err
		}
	}
	SetSyncInterval.decodeRequest = func(reader io.Reader) (r SyncIntervalRequest, err error) {
		fields, err := syncRequestFields(reader, SetSyncInterval.definition.Path)
		if err == nil {

View on GitHub (pinned to 9f775e8a12)