siyuan-note/siyuan · error
invalid jsonrpc version
Error message
invalid jsonrpc version: %s
What it means
JsonRpcRequest.UnmarshalJSON requires the jsonrpc member to equal the supported JsonRpcVersion ("2.0"). When the field is present but holds any other value, unmarshalling fails with 'invalid jsonrpc version: %s' including the received value. This rejects JSON-RPC 1.x messages and typo'd version strings.
Solutions
- Set the field to the exact string "jsonrpc": "2.0" (no spaces, no suffix)
- Ensure the value is serialized as a string, not the number 2.0
- Check the client library's protocol version setting and switch it to 2.0
- Read the reported version value in the error message to see exactly what was received
Example fix
// before
{"jsonrpc": 2.0, "method": "ping", "id": 1}
// after
{"jsonrpc": "2.0", "method": "ping", "id": 1} Defensive patterns
Strategy: validation
Validate before calling
if (body.jsonrpc !== "2.0") throw new Error(`jsonrpc must be exactly "2.0", got ${JSON.stringify(body.jsonrpc)}`); Type guard
const isJsonRpc2 = (body) => body && typeof body.jsonrpc === "string" && body.jsonrpc === "2.0";
Try / catch
try { return await rpcSend(payload); } catch (e) { if (String(e).startsWith("invalid jsonrpc version")) { payload.jsonrpc = "2.0"; return rpcSend(payload); } throw e; } Prevention
- Hard-code the exact string "2.0", never interpolate or localize it
- Serialize jsonrpc as a string, not the number 2.0
- Set client library protocol version to 2.0
- Read the received value in the error message when diagnosing
When it happens
Trigger: Sending "jsonrpc":"1.0", "jsonrpc":"2.0-rc", "jsonrpc":"JSON-RPC 2.0", or a numeric jsonrpc: 2.0 (which decodes to "2.0"? no — as string field it errors on decode/type); any non-exact "2.0" string.
Common situations: Clients written against JSON-RPC 1.1/1.0; copy-pasted payloads with quoted or decorated version strings; serializers emitting numeric 2.0 instead of the string "2.0".
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- invalid jsonrpc version
- invalid id field: must be string, number, null or omitted
- missing jsonrpc field
- missing method field
- RPC call requires a request or error
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/8870a8f7fdf37128.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/plugin/rpc.go:116
decoder := json.NewDecoder(bytes.NewReader(data))
// decoder.DisallowUnknownFields() // Reject unknown fields violates the JSON-RPC spec
type JsonRpcRequestObject struct {
JsonRpc util.Optional[string] `json:"jsonrpc"`
Method util.Optional[string] `json:"method"`
Params util.Optional[any] `json:"params"`
ID util.Optional[any] `json:"id"`
}
request := JsonRpcRequestObject{}
if err := decoder.Decode(&request); err != nil {
return err
}
// Validate jsonrpc field
if !request.JsonRpc.Exists {
return fmt.Errorf("missing jsonrpc field")
}
if request.JsonRpc.Value != JsonRpcVersion {
return fmt.Errorf("invalid jsonrpc version: %s", request.JsonRpc.Value)
}
// Validate method field
if !request.Method.HasValue() {
return fmt.Errorf("missing method field")
}
// Validate id field
if !request.ID.Exists {
} else if request.ID.IsNull {
} else if _, ok := request.ID.Value.(string); ok {
} else if _, ok := request.ID.Value.(float64); ok {
} else {
return fmt.Errorf("invalid id field: must be string, number, null or omitted")
}
r.JsonRpc = request.JsonRpc.Value
r.Method = request.Method.ValueView on GitHub (pinned to 9f775e8a12)