Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Plugin JsonRpcResponse uses id: u64, so plugin error responses with id: null (parse errors, invalid requests) fail deserialization and hang the caller

Open
#916 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
75/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
json, rust, tauri
Domain
api, backend

Research direction

Read src-tauri/src/plugins/rpc.rs and the response handling in driver.rs around lines 262–275. Check how JsonRpcResponse is deserialized and how pending requests are resolved; run the relevant plugin RPC tests, if available. Done means responses with id: null deserialize without leaving a caller waiting, while normal response handling still works.

Written by the indexing model from the issue text.

Description

Problem

The plugin host's JsonRpcResponse type deserializes the id field as
u64 (not nullable), but the JSON-RPC 2.0 spec requires id: null in error
responses when the request id can't be determined (parse errors -32700,
invalid requests -32600). When a plugin sends such a response, the host
fails to deserialize it, logs "Failed to parse plugin response", discards the
line, and the pending request's oneshot::Sender is never resolved — the
caller hangs until the call timeout fires.

Cause

JsonRpcResponse in src-tauri/src/plugins/rpc.rs (lines 41-54):

#[derive(Serialize, Deserialize, Debug)]
#[serde(untagged)]
pub enum JsonRpcResponse {
    Success {
        jsonrpc: String,
        result: Value,
        id: u64,
    },
    Error {
        jsonrpc: String,
        error: JsonRpcError,
        id: u64,
    },
}

Both variants use id: u64. When the plugin sends {"jsonrpc":"2.0", "error":{"code":-32700,"message":"parse error: ..."},"id":null} (or
-32600), serde_json::from_str::<JsonRpcResponse> fails because null
is not a valid u64. The #[serde(untagged)] enum tries Success (no
result field → fails) then Error (null is not u64 → fails), returns
Err, and the host discards the line at driver.rs:273-275:

Err(e) => {
    log::error!("Failed to parse plugin response: {}", e);
}

The pending_requests map still holds the caller's oneshot::Sender, so the
caller hangs until the call timeout fires — the same hang the plugin's #135
fix was meant to prevent.

When this triggers

  • Parse error (-32700): the plugin sends id: null for any line that
    isn't valid JSON (e.g. a garbled stdin line). Pre-existing — this path has
    always sent id: null.
  • Invalid request (-32600): the plugin sends id: null for a non-object
    JSON-RPC line (array, number, string, bool, null). Added by
    tabularis-postgresql-plugin#135 (PR #136).
  • Any future plugin error response where the id is undeterminable.

In all cases the plugin is spec-correct; the host can't consume the response.

Suggested fix

Change id to Option<u64> (or serde_json::Value) in both variants:

pub enum JsonRpcResponse {
    Success {
        jsonrpc: String,
        result: Value,
        id: Option<u64>,
    },
    Error {
        jsonrpc: String,
        error: JsonRpcError,
        id: Option<u64>,
    },
}

Then update the two match arms in driver.rs (lines 263-271) to handle
None — there's no pending request to match (the request id couldn't be
determined), so log and discard, which is already what happens when
pending_requests.remove(&id) finds nothing:

Ok(JsonRpcResponse::Success { result, id, .. }) => {
    if let Some(id) = id {
        if let Some(tx) = pending_requests.remove(&id) {
            let _ = tx.send(Ok(result));
        }
    }
}
Ok(JsonRpcResponse::Error { error, id, .. }) => {
    if let Some(id) = id {
        if let Some(tx) = pending_requests.remove(&id) {
            let _ = tx.send(Err(PluginCallError::Remote(error)));
        }
    }
}

This is a one-file change in src-tauri/src/plugins/rpc.rs plus the two match
arms in driver.rs. The JsonRpcResponse type is only consumed by
driver.rs (the MCP JsonRpcResponse in src-tauri/src/mcp/protocol.rs is a
separate struct, not affected).

Scope

This is the host-side companion to tabularis-postgresql-plugin#135/#137. The
plugin correctly sends id: null per JSON-RPC 2.0; the host just can't
deserialize it. Confirmed by reading the source: id: u64 in rpc.rs:47,52,
deserialization at driver.rs:262, discard at driver.rs:273-275.

Surfaced by /code-review on tabularis-postgresql-plugin PR #136.

Dominant language
TypeScript
Stars
5.1k
Forks
335
Avg merge
1d 22h
Merged PRs (30d)
75

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from TabularisDB/tabularis

All issues in TabularisDB/tabularis

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.