cli, rpc: add -rpcid option for custom request IDs #35006

pull torkelrogstad wants to merge 1 commits into bitcoin:master from torkelrogstad:2026-04-05-request-id changing 3 files +21 −4
  1. torkelrogstad commented at 1:05 PM on April 5, 2026: contributor

    Add a -rpcid CLI argument to bitcoin-cli that allows setting a custom string as the JSON-RPC request ID instead of the hardcoded default of 1. This enables correlating requests and responses when debugging or when multiple clients are making concurrent calls.

    On the server side, include the request ID in the RPC debug log line when it differs from the default value of 1, so that custom IDs are visible in the debug.log output.

    Tests are added in test/functional/interface_bitcoin_cli.py for this.

  2. DrahtBot commented at 1:05 PM on April 5, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK stickies-v

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #35015 (bitcoin-cli: note -rpcclienttimeout is not implemented for IPC connections by ryanofsky)
    • #31260 (scripted-diff: Type-safe settings retrieval by ryanofsky)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  3. in src/rpc/request.cpp:236 in a2ecbc60e4
     232 | @@ -233,11 +233,13 @@ void JSONRPCRequest::parse(const UniValue& valRequest)
     233 |      if (!valMethod.isStr())
     234 |          throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
     235 |      strMethod = valMethod.get_str();
     236 | +    const bool log_id{id && !id->isNull() && id->getValStr() != "1"};
    


    stickies-v commented at 6:14 PM on April 14, 2026:

    I don't see the need to couple rpc and cli here, just always logging the rpcid seems good? Simplifies behaviour and implementation.


    torkelrogstad commented at 10:50 AM on April 15, 2026:

    The idea was that including the ID if set to the default value would lead to more noise in the logs, without providing any benefit to the log consumer. Just loads and loads of log lines with ID "1". One idea would be to actually generate random IDs, instead of hard coding a value? Could do a dash-less UUID, for example.


    stickies-v commented at 4:43 PM on April 15, 2026:

    would lead to more noise in the logs

    It's a debug log, and we're not adding any new lines, just a few characters. Doesn't seem like a big deal to me.

    I think it's orthogonal to this PR, but defaulting to something like bitcoin-cli-<version> instead of 1 could be sensible. What benefit would a random ID provide when it's not returned to the user?


    torkelrogstad commented at 5:08 PM on April 15, 2026:

    I like the idea of changing the default to bitcoin-cli-<version>! But agree on your points wrt. orthogonality and simplicity. Will fix!

  4. in src/bitcoin-cli.cpp:103 in a2ecbc60e4
      99 | @@ -100,6 +100,7 @@ static void SetupCliArgs(ArgsManager& argsman)
     100 |      SetupChainParamsBaseOptions(argsman);
     101 |      argsman.AddArg("-color=<when>", strprintf("Color setting for CLI output (default: %s). Valid values: always, auto (add color codes when standard output is connected to a terminal and OS is not WIN32), never. Only applies to the output of -getinfo.", DEFAULT_COLOR_SETTING), ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::OPTIONS);
     102 |      argsman.AddArg("-named", strprintf("Pass named instead of positional arguments (default: %s)", DEFAULT_NAMED), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     103 | +    argsman.AddArg("-rpcid=<id>", "Set a custom JSON-RPC request ID string (default: 1)", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION | ArgsManager::DISALLOW_ELISION, OptionsCategory::OPTIONS);
    


    stickies-v commented at 7:26 PM on April 14, 2026:

    nit: would be nice to parameterize DEFAULT_RPC_REQ_ID

  5. in src/bitcoin-cli.cpp:796 in a2ecbc60e4
     792 | +        UniValue id;
     793 | +        if (auto rpcid = gArgs.GetArg("-rpcid")) {
     794 | +            id = UniValue(UniValue::VSTR, *rpcid);
     795 | +        } else {
     796 | +            id = UniValue(1);
     797 | +        }
    


    stickies-v commented at 7:42 PM on April 14, 2026:

    Since we're casting the rpcid arg to VSTR, I think it's reasonable to also have the default value be a string, in which case this can be simplified:

    <details> <summary>git diff on a2ecbc60e4</summary>

    diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
    index b6aa478719..3455aea73b 100644
    --- a/src/bitcoin-cli.cpp
    +++ b/src/bitcoin-cli.cpp
    @@ -57,6 +57,7 @@ using CliClock = std::chrono::system_clock;
     const TranslateFn G_TRANSLATION_FUN{nullptr};
     
     static const char DEFAULT_RPCCONNECT[] = "127.0.0.1";
    +static constexpr const char* DEFAULT_RPC_REQ_ID{"1"};
     static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
     static constexpr int DEFAULT_WAIT_CLIENT_TIMEOUT = 0;
     static const bool DEFAULT_NAMED=false;
    @@ -100,7 +101,7 @@ static void SetupCliArgs(ArgsManager& argsman)
         SetupChainParamsBaseOptions(argsman);
         argsman.AddArg("-color=<when>", strprintf("Color setting for CLI output (default: %s). Valid values: always, auto (add color codes when standard output is connected to a terminal and OS is not WIN32), never. Only applies to the output of -getinfo.", DEFAULT_COLOR_SETTING), ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::OPTIONS);
         argsman.AddArg("-named", strprintf("Pass named instead of positional arguments (default: %s)", DEFAULT_NAMED), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
    -    argsman.AddArg("-rpcid=<id>", "Set a custom JSON-RPC request ID string (default: 1)", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION | ArgsManager::DISALLOW_ELISION, OptionsCategory::OPTIONS);
    +    argsman.AddArg("-rpcid=<id>", strprintf("Set a custom JSON-RPC request ID string (default: %s)", DEFAULT_RPC_REQ_ID), ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION | ArgsManager::DISALLOW_ELISION, OptionsCategory::OPTIONS);
         argsman.AddArg("-rpcclienttimeout=<n>", strprintf("Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d)", DEFAULT_HTTP_CLIENT_TIMEOUT), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
         argsman.AddArg("-rpcconnect=<ip>", strprintf("Send commands to node running on <ip> (default: %s)", DEFAULT_RPCCONNECT), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
         argsman.AddArg("-rpccookiefile=<loc>", "Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
    @@ -788,12 +789,7 @@ struct DefaultRequestHandler : BaseRequestHandler {
             } else {
                 params = RPCConvertValues(method, args);
             }
    -        UniValue id;
    -        if (auto rpcid = gArgs.GetArg("-rpcid")) {
    -            id = UniValue(UniValue::VSTR, *rpcid);
    -        } else {
    -            id = UniValue(1);
    -        }
    +        UniValue id{UniValue::VSTR, gArgs.GetArg("-rpcid", DEFAULT_RPC_REQ_ID)};
             return JSONRPCRequestObj(method, params, id);
         }
     
    
    

    </details>

  6. stickies-v commented at 7:43 PM on April 14, 2026: contributor

    Concept ACK

    I think this can be simplified as per my comments.

  7. torkelrogstad force-pushed on Apr 15, 2026
  8. torkelrogstad commented at 5:17 PM on April 15, 2026: contributor

    Addressed and fixed review from @stickies-v. Thanks!

  9. in src/rpc/request.cpp:236 in 2ad6416eb2
     232 | @@ -233,11 +233,13 @@ void JSONRPCRequest::parse(const UniValue& valRequest)
     233 |      if (!valMethod.isStr())
     234 |          throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
     235 |      strMethod = valMethod.get_str();
     236 | +    const std::string log_id{id && !id->isNull() ? strprintf(" id=%s", id->getValStr()) : ""};
    


    stickies-v commented at 5:29 PM on April 15, 2026:

    I would really prefer to avoid nesting fmt strings, it's so much harder to read. Just printing an empty "id=" in case of null seems straightforward, consistent and simple.

    nit: log lines no longer need a newline at the end, so would be good to clean up while they're touched.

    <details> <summary>git diff on 2ad6416eb2</summary>

    diff --git a/src/rpc/request.cpp b/src/rpc/request.cpp
    index acfd85b0b0..e1d48eb8ed 100644
    --- a/src/rpc/request.cpp
    +++ b/src/rpc/request.cpp
    @@ -233,13 +233,13 @@ void JSONRPCRequest::parse(const UniValue& valRequest)
         if (!valMethod.isStr())
             throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
         strMethod = valMethod.get_str();
    -    const std::string log_id{id && !id->isNull() ? strprintf(" id=%s", id->getValStr()) : ""};
    +    auto req_id{id.value_or(UniValue{}).getValStr()};
         if (fLogIPs)
    -        LogDebug(BCLog::RPC, "ThreadRPCServer method=%s user=%s peeraddr=%s%s\n", SanitizeString(strMethod),
    -            this->authUser, this->peerAddr, log_id);
    +        LogDebug(BCLog::RPC, "ThreadRPCServer method=%s user=%s peeraddr=%s id=%s", SanitizeString(strMethod),
    +            this->authUser, this->peerAddr, req_id);
         else
    -        LogDebug(BCLog::RPC, "ThreadRPCServer method=%s user=%s%s\n", SanitizeString(strMethod), this->authUser,
    -            log_id);
    +        LogDebug(BCLog::RPC, "ThreadRPCServer method=%s user=%s id=%s", SanitizeString(strMethod), this->authUser,
    +        req_id);
     
         // Parse params
         const UniValue& valParams{request.find_value("params")};
    
    

    </details>

  10. torkelrogstad force-pushed on Apr 16, 2026
  11. torkelrogstad commented at 5:24 AM on April 16, 2026: contributor

    Pushed a fix for the nested log line. Also realized we should be sanitizing the request ID before logging!

  12. DrahtBot added the label CI failed on Apr 16, 2026
  13. DrahtBot commented at 6:12 AM on April 16, 2026: contributor

    <!--85328a0da195eb286784d51f73fa0af9-->

    🚧 At least one of the CI tasks failed. <sub>Task lint: https://github.com/bitcoin/bitcoin/actions/runs/24493663393/job/71583785799</sub> <sub>LLM reason (✨ experimental): CI failed due to a lint trailing_whitespace violation (trailing space in src/rpc/request.cpp:236).</sub>

    <details><summary>Hints</summary>

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

    </details>

  14. cli, rpc: add -rpcid option for custom request IDs
    Add a -rpcid CLI argument to bitcoin-cli that allows setting a custom
    string as the JSON-RPC request ID instead of the hardcoded default of 1.
    This enables correlating requests and responses when debugging or when
    multiple clients are making concurrent calls.
    
    On the server side, include the request ID in the RPC debug log line
    when it differs from the default value of 1, so that custom IDs are
    visible in the debug.log output.
    c54f37c1ba
  15. torkelrogstad force-pushed on Apr 16, 2026
  16. stickies-v approved
  17. stickies-v commented at 2:16 PM on April 16, 2026: contributor

    ACK c54f37c1ba9f825fbcbcd7276fa4a2d911aae18d

  18. DrahtBot removed the label CI failed on Apr 16, 2026

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-04-18 15:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me