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

After confirming the id is valid JSON, PluginRPCID.UnmarshalJSON enforces the JSON-RPC id rules: it must be a string (starts with '"'), a number (starts with '-' or 0-9), or the literal null. Any other JSON value — typically an object or array — is rejected with "invalid id field: must be string, number, null or omitted".

Solutions

  1. Change the id to a plain string or number (or null) as required by the JSON-RPC id specification.
  2. Move any extra correlation metadata into params instead of the id field.
  3. Fix the client's id type declaration so it serializes as a scalar.

Example fix

// before
{"id": {"requestId": 42}}
// after
{"id": 42}
Defensive patterns

Strategy: validation

Validate before calling

function checkRpcIdShape(id) {
  if (!(typeof id === "string" || (typeof id === "number" && Number.isFinite(id)) || id === null)) {
    throw new Error("id must be a JSON-RPC scalar: string, number, or null");
  }
}

Type guard

const isScalarRpcId = (id) => id === null || typeof id === "string" || (typeof id === "number" && !Number.isNaN(id));

Try / catch

try { await rpcCall(method, params, id); } catch (e) { if (String(e).includes("invalid id field")) { throw new Error("wrap id metadata into params; id must stay a scalar"); } throw e; }

Prevention

When it happens

Trigger: Unmarshalling a plugin RPC message whose id is a JSON object or array (data[0] is '{' or '['), e.g. {"id": {"n": 1}} or {"id": ["a"]}.

Common situations: A client library that types id as a generic object serializes a structured id; correlation IDs wrapped in objects for extra metadata; mismatched RPC dialects between plugin and kernel.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at kernel/apicontract/plugin_rpc.go:20

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"strings"
)

type PluginRPCID struct{ value JSONValue }

func (id PluginRPCID) MarshalJSON() ([]byte, error) { return json.Marshal(id.value) }
func (id *PluginRPCID) UnmarshalJSON(data []byte) error {
	data = bytes.TrimSpace(data)
	if !json.Valid(data) || len(data) == 0 {
		return fmt.Errorf("invalid RPC ID")
	}
	if data[0] != '"' && data[0] != '-' && (data[0] < '0' || data[0] > '9') && string(data) != "null" {
		return fmt.Errorf("invalid id field: must be string, number, null or omitted")
	}
	return json.Unmarshal(data, &id.value)
}

type PluginRPCParams struct{ value JSONValue }

type PluginRPCRequestFields struct {
	JSONRPC string           `json:"jsonrpc" api:"const=\"2.0\""`
	Method  string           `json:"method"`
	Params  *PluginRPCParams `json:"params" api:"optional"`
	ID      *PluginRPCID     `json:"id" api:"optional"`
}

type PluginRPCSuccess struct {
	JSONRPC string      `json:"jsonrpc" api:"const=\"2.0\""`
	Result  JSONValue   `json:"result"`
	ID      PluginRPCID `json:"id"`
}

View on GitHub (pinned to 9f775e8a12)