{"record":{"id":"ab679e8f81dad770","repo":"siyuan-note/siyuan","slug":"missing-jsonrpc-field","errorCode":null,"errorMessage":"missing jsonrpc field","messagePattern":"missing jsonrpc field","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/plugin/rpc.go","lineNumber":113,"sourceCode":"}\n\nfunc (r *JsonRpcRequest) UnmarshalJSON(data []byte) error {\n\tdecoder := json.NewDecoder(bytes.NewReader(data))\n\t// decoder.DisallowUnknownFields() // Reject unknown fields violates the JSON-RPC spec\n\ttype JsonRpcRequestObject struct {\n\t\tJsonRpc util.Optional[string] `json:\"jsonrpc\"`\n\t\tMethod  util.Optional[string] `json:\"method\"`\n\t\tParams  util.Optional[any]    `json:\"params\"`\n\t\tID      util.Optional[any]    `json:\"id\"`\n\t}\n\trequest := JsonRpcRequestObject{}\n\tif err := decoder.Decode(&request); err != nil {\n\t\treturn err\n\t}\n\n\t// Validate jsonrpc field\n\tif !request.JsonRpc.Exists {\n\t\treturn fmt.Errorf(\"missing jsonrpc field\")\n\t}\n\tif request.JsonRpc.Value != JsonRpcVersion {\n\t\treturn fmt.Errorf(\"invalid jsonrpc version: %s\", request.JsonRpc.Value)\n\t}\n\n\t// Validate method field\n\tif !request.Method.HasValue() {\n\t\treturn fmt.Errorf(\"missing method field\")\n\t}\n\n\t// Validate id field\n\tif !request.ID.Exists {\n\t} else if request.ID.IsNull {\n\t} else if _, ok := request.ID.Value.(string); ok {\n\t} else if _, ok := request.ID.Value.(float64); ok {\n\t} else {\n\t\treturn fmt.Errorf(\"invalid id field: must be string, number, null or omitted\")\n\t}","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/plugin/rpc.go#L95-L131","documentation":"JsonRpcRequest.UnmarshalJSON validates incoming JSON-RPC 2.0 messages before dispatch. The 'jsonrpc' member is mandatory and must be exactly the supported version string; when the raw message lacks the jsonrpc field entirely, unmarshalling fails with 'missing jsonrpc field'. This enforces the JSON-RPC 2.0 spec requirement that every request carry a jsonrpc member.","triggerScenarios":"Posting a JSON body to the plugin RPC endpoint without a \"jsonrpc\" key, e.g. {\"method\":\"x\",\"id\":1}; clients built for JSON-RPC 1.0 or ad-hoc protocols omitting the field; hand-crafted curl/test payloads.","commonSituations":"Developers testing the RPC endpoint with curl or Postman using a minimal body; custom MCP/JSON-RPC clients that forgot the version field; middleware stripping unknown fields from payloads.","solutions":["Add \"jsonrpc\": \"2.0\" to every request body","Verify the exact payload sent with a network capture or by logging the raw body before unmarshal","If using a client library, configure the JSON-RPC 2.0 mode rather than raw JSON posting","Retest with a known-good minimal request: {\"jsonrpc\":\"2.0\",\"method\":\"ping\",\"id\":1}"],"exampleFix":"// before\n{\"method\": \"ping\", \"id\": 1}\n// after\n{\"jsonrpc\": \"2.0\", \"method\": \"ping\", \"id\": 1}","handlingStrategy":"validation","validationCode":"function buildRpcRequest(method, params, id) { return { jsonrpc: \"2.0\", method, ...(params !== undefined ? { params } : {}), ...(id !== undefined ? { id } : {}) }; }","typeGuard":"const hasJsonRpcField = (body) => body && typeof body === \"object\" && typeof body.jsonrpc === \"string\";","tryCatchPattern":"try { return await rpcSend(payload); } catch (e) { if (String(e).includes(\"missing jsonrpc field\")) { console.error(\"payload sent:\", JSON.stringify(payload)); } throw e; }","preventionTips":["Always include \"jsonrpc\": \"2.0\" in every request","Use a JSON-RPC 2.0 client library or a shared request builder","Log raw payloads when debugging RPC failures","Add a payload schema test for your RPC client"],"tags":["json-rpc","validation","protocol"],"backgroundTag":"schema-validation-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"}