siyuan-note/siyuan · error
RPC reply requires a response or error
Error message
RPC reply requires a response or error
What it means
pluginRPCReply converts an internal JsonRpcProcessingResponse into an apicontract.PluginRPCReply. A response must carry either a Result (success) or an Error; if response.Error is nil after the success path was not taken, the reply is unusable and this error is thrown.
Solutions
- Set response.Error to a JsonRpcProcessingError whenever the call did not succeed
- Fix the dispatch path so every response is either RPCSuccessReply or carries a populated Error
- Check that the success encoding path did not silently drop the response before reaching the error branch
- Add a pre-check validating Result-or-Error presence before calling pluginRPCReply
Example fix
// before
resp := JsonRpcProcessingResponse{}
reply, err := pluginRPCReply(resp)
// after
resp := JsonRpcProcessingResponse{Error: &JsonRpcProcessingError{Code: -32603, Message: "internal error"}}
reply, err := pluginRPCReply(resp) Defensive patterns
Strategy: validation
Validate before calling
if resp.Result == nil && resp.Error == nil {
return fmt.Errorf("response must carry result or error")
} Type guard
func replyable(r JsonRpcProcessingResponse) bool { return r.Error != nil } Try / catch
reply, err := pluginRPCReply(resp)
if err != nil {
reply = apicontract.RPCFailureReply(id, -32603, err.Error())
} Prevention
- Set Error on every non-successful response before calling pluginRPCReply
- Never construct zero-value JsonRpcProcessingResponse structs
- Cover both success and failure reply paths in unit tests
When it happens
Trigger: Calling pluginRPCReply with a JsonRpcProcessingResponse whose Result was not encodable into a success reply and whose Error field is nil — e.g. a zero-value response struct, or a handler that returned neither a result nor an error.
Common situations: Constructing JsonRpcProcessingResponse manually in tests; a dispatch path that forgets to set response.Error when the plugin call fails without producing a result; type changes in the response struct leaving fields unset.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- RPC call requires a request or error
- first argument must be method name string
- invalid id field: must be string, number, null or omitted
- invalid id field: must be string, number, null or omitted
- invalid jsonrpc version
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/7100d2e49be5c440.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/plugin/rpc_contract.go:159
if response.Response != nil {
value := response.Response
result, err := json.Marshal(value.Result)
if err != nil {
return apicontract.PluginRPCReply{}, err
}
encoded, err := apicontract.EncodedJSONValue(result)
if err != nil {
return apicontract.PluginRPCReply{}, err
}
id, err := pluginRPCID(value.ID)
if err != nil {
return apicontract.PluginRPCReply{}, err
}
return apicontract.RPCSuccessReply(apicontract.PluginRPCSuccess{JSONRPC: value.JsonRpc, Result: encoded, ID: id}), nil
}
value := response.Error
if value == nil {
return apicontract.PluginRPCReply{}, fmt.Errorf("RPC reply requires a response or error")
}
id, err := pluginRPCID(value.ID)
if err != nil {
return apicontract.PluginRPCReply{}, err
}
result := apicontract.PluginRPCFailure{JSONRPC: value.JsonRpc, ID: id}
if value.Error != nil {
result.Error = &apicontract.PluginRPCError{Code: int(value.Error.Code), Message: value.Error.Message}
if value.Error.Data != nil {
data, err := json.Marshal(value.Error.Data)
if err != nil {
return apicontract.PluginRPCReply{}, err
}
encoded, err := apicontract.EncodedJSONValue(data)
if err != nil {
return apicontract.PluginRPCReply{}, err
}
result.Error.Data = &encodedView on GitHub (pinned to 9f775e8a12)