siyuan-note/siyuan · error
invalid id field: must be string, number, null or omitted
Error message
invalid id field: must be string, number, null or omitted
What it means
JSON-RPC 2.0 restricts the 'id' member to string, number, or null (or the field may be omitted for notifications). JsonRpcRequest.UnmarshalJSON enforces this: if id exists, is not null, and is neither string nor float64, it fails with 'invalid id field: must be string, number, null or omitted'. This keeps correlation IDs spec-compliant so responses can be matched to requests.
Solutions
- Use a string or number for id, or omit it entirely for notifications
- Replace boolean/object id values with a generated numeric or string identifier
- Validate the payload schema before sending (id must be scalar or null)
- Check client library settings for automatic ID generation and force scalar IDs
Example fix
// before
{"jsonrpc": "2.0", "method": "ping", "id": true}
// after
{"jsonrpc": "2.0", "method": "ping", "id": "req-1"} Defensive patterns
Strategy: validation
Validate before calling
function validId(id) { return id === undefined || id === null || typeof id === "string" || typeof id === "number"; } Type guard
const isRpcId = (v) => v === undefined || v === null || typeof v === "string" || (typeof v === "number" && Number.isFinite(v));
Try / catch
try { return await rpcSend(payload); } catch (e) { if (String(e).includes("invalid id field")) { payload.id = String(payload.id); return rpcSend(payload); } throw e; } Prevention
- Restrict ids to strings or finite numbers; never booleans, arrays, or objects
- Generate ids via a counter or UUID string
- Omit id entirely for notifications instead of sending null-like placeholders
- Add a schema check for id in your RPC client's send path
When it happens
Trigger: Sending "id": true/false (boolean), "id": {"n":1} (object), or "id": [1] (array); clients auto-generating UUID objects instead of strings; batching frameworks that inject non-scalar IDs.
Common situations: Custom clients using boolean flags as IDs; JavaScript engines passing objects; test scripts with id: true to mean 'request'; serializers that box numbers into objects.
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.
Related errors
- attr must be a string or null (got %T)
- block [ ] type is locked: expected , got
- createDocTree definition must be a list
- createDocTree document must be a dictionary
- date display format is only available for date fields
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/0532073b55a83671.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/plugin/rpc.go:130
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.Value
r.Params = request.Params
r.ID = request.ID
return nil
}
// IsNotification returns true if this request is a notification (no ID field).
func (r *JsonRpcRequest) IsNotification() bool {
return r.ID.Exists == false
}
// Validate validates the JSON-RPC request structure.
func (r *JsonRpcRequest) Validate() *JsonRpcError {
// params is optional, but if present must be either an array (for positional parameters) or an object (for named parameters)
if !r.Params.Exists {View on GitHub (pinned to 9f775e8a12)