{
 "number": 17493,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/17493",
 "title": "util: Forbid ambiguous multiple assignments in config file",
 "author": "ryanofsky",
 "author_association": "MEMBER",
 "created_at": "2019-11-15T22:11:44Z",
 "updated_at": "2026-09-13T15:55:20Z",
 "age_days": 2497,
 "draft": true,
 "labels": [
  "Refactoring",
  "Utils/log/libs"
 ],
 "milestone": null,
 "base": "master",
 "head_sha": "31de2cc896f63f11d2abdbf7640f4b657bf87b78",
 "head_ref": "pr/wdmult",
 "head_repo": "ryanofsky/bitcoin",
 "head_history": [
  {
   "t": "2019-11-21T22:50:33Z",
   "sha": "c011a7f09af7916a85fb6a6c54ebcb2302f9268b"
  },
  {
   "t": "2019-11-24T20:10:10Z",
   "sha": "4a79e385b6ee8712ab3f43f43e519b86bc19f505"
  },
  {
   "t": "2019-12-20T16:03:38Z",
   "sha": "39207eed6cf2a3e8b8e09e52387e31421a66e340"
  },
  {
   "t": "2020-09-28T12:57:03Z",
   "sha": "77623d1dc643f9a69476cb1297d223bad786a972"
  },
  {
   "t": "2021-04-13T03:10:29Z",
   "sha": "53c19cd8310ef2187bf3ef430a53d83a6e5c0414"
  },
  {
   "t": "2021-06-16T20:26:37Z",
   "sha": "7a66e8a1e3b420022f7116529f7b078b3604eaa9"
  },
  {
   "t": "2021-12-30T21:19:24Z",
   "sha": "ca8d268011b53315652535bab86db95d2ec4c4f2"
  },
  {
   "t": "2022-09-27T18:23:17Z",
   "sha": "bcd3e36d6e977e59ea542ff74242c0a538f741a0"
  },
  {
   "t": "2022-11-29T23:28:51Z",
   "sha": "0401590f645af27bbce6409a1d06aa127378ce33"
  },
  {
   "t": "2023-02-15T02:54:56Z",
   "sha": "20ace2d096420974689fe18b8fa73d120d7c6d10"
  },
  {
   "t": "2023-05-03T21:20:35Z",
   "sha": "c65e3b3b7d1e9dc33ecf5f0029430ef90f765cf8"
  },
  {
   "t": "2024-07-19T23:07:26Z",
   "sha": "67bbec94c33f1e117fdd26d130ec68724e64ea17"
  },
  {
   "t": "2024-08-06T16:41:01Z",
   "sha": "6a42b8e1d4ef89dda7237d2fee3fe70092928441"
  },
  {
   "t": "2024-12-06T18:59:34Z",
   "sha": "ec1698a0a37015bbc9323d1d72428f57d780050b"
  },
  {
   "t": "2025-03-12T18:22:46Z",
   "sha": "e064f20d8a8a3746040ccde52ef3b4b492aa858a"
  },
  {
   "t": "2025-08-04T17:51:10Z",
   "sha": "98e2bba7054c82eeddf1f5565362ec901207aeda"
  },
  {
   "t": "2025-12-12T12:18:57Z",
   "sha": "68d1b626ac2fc7d5293bd9e70985fbf899decff8"
  },
  {
   "t": "2025-12-16T02:10:17Z",
   "sha": "20119c310f4e280488c310427e1fa58f7056e81a"
  },
  {
   "t": "2026-01-18T23:06:34Z",
   "sha": "24078e372fa35717e3330721914136ab14a19834"
  },
  {
   "t": "2026-04-01T21:50:24Z",
   "sha": "ab0963226f8c4816d8e84ee01073de19a5913ffb"
  },
  {
   "t": "2026-06-08T16:41:11Z",
   "sha": "b6794bddf85340b0e1d52d73f831fd45c8f0ef19"
  },
  {
   "t": "2026-06-24T15:28:15Z",
   "sha": "0e4d6342ffa6d4f9b5046c63b1bd2576b60ee00a"
  },
  {
   "t": "2026-08-15T16:11:18Z",
   "sha": "31de2cc896f63f11d2abdbf7640f4b657bf87b78"
  }
 ],
 "additions": 1196,
 "deletions": 203,
 "changed_files": 16,
 "commit_count": 17,
 "size_bucket": "XL",
 "mergeable_state": "clean",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "concept_nack": [
     {
      "login": "ajtowns",
      "url": "https://github.com/bitcoin/bitcoin/pull/17493#issuecomment-572391776"
     }
    ],
    "concept_ack": [
     {
      "login": "JeremyRubin",
      "url": "https://github.com/bitcoin/bitcoin/pull/17493#pullrequestreview-318636254"
     }
    ]
   },
   "conflicts": [
    {
     "number": 35940,
     "title": "net: allow selecting BIP152 high-bandwidth peers with `-addnode`",
     "author": "w0xlt"
    },
    {
     "number": 35387,
     "title": "logging: make trace logging easily usable",
     "author": "ryanofsky"
    },
    {
     "number": 35322,
     "title": "logging: streamline Logger state and drop redundant methods",
     "author": "ryanofsky"
    },
    {
     "number": 35037,
     "title": "ipc: support per-address max-connections options on -ipcbind",
     "author": "enirox001"
    },
    {
     "number": 35027,
     "title": "net: add -outboundbind option for outgoing source address",
     "author": "8144225309"
    },
    {
     "number": 34038,
     "title": "logging: replace -loglevel with -trace, expose trace logging via RPC",
     "author": "ajtowns"
    },
    {
     "number": 16545,
     "title": "refactor: Implement missing error checking for ArgsManager flags",
     "author": "ryanofsky"
    }
   ]
  }
 },
 "acks_parsed": {
  "JeremyRubin": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2019-11-18T21:23:22Z",
   "stale": false
  }
 },
 "acks_tally": {
  "ack": 0,
  "stale_ack": 0,
  "concept_ack": 1,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 1,
  "changes_requested": 0,
  "distinct_reviewers": [
   "JeremyRubin",
   "Khailand69",
   "ajtowns",
   "fanquake"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "clean",
  "last_author_activity": "2026-08-15T16:11:18Z",
  "last_reviewer_activity": "2023-02-08T11:25:36Z",
  "last_reviewer": "fanquake",
  "author_silent_days": 33,
  "waiting_on_author_days": 0,
  "days_since_update": 4
 },
 "refs": {
  "mentioned": [
   12763,
   15629,
   16545,
   17580,
   17581,
   35441
  ],
  "depends_on": [
   16545
  ],
  "fixes": [],
  "linked_issues": [],
  "references": [
   {
    "number": 16545,
    "type": "pull",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "refactor: Implement missing error checking for ArgsManager flags"
   },
   {
    "number": 17580,
    "type": "pull",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "refactor: Add ALLOW_LIST flags and enforce usage in CheckArgFlags"
   },
   {
    "number": 17581,
    "type": "pull",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "refactor: Remove settings merge reverse precedence code"
   },
   {
    "number": 12763,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2019-12-13",
    "title": "Add RPC Whitelist Feature from #12248"
   },
   {
    "number": 15629,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2019-04-10",
    "title": "init: Throw error when network specific config is ignored"
   },
   {
    "number": 35441,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-06-15",
    "title": "ci: inline runner selection"
   }
  ],
  "conflicts": [
   35940,
   35387,
   35322,
   35037,
   35027,
   34038,
   16545
  ]
 },
 "stack": {
  "shares_commits_with": [
   17580,
   17581,
   17783
  ],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [
  "src/util/system.cpp"
 ],
 "body": "**This is based on #16545 + #17580.** The non-base commits are:\n\n- [`9a22b9caf6f` util: Forbid ambiguous multiple assignments in config file](https://github.com/bitcoin/bitcoin/pull/17493/commits/9a22b9caf6f6236e4fa84aef3c23b60cb758c7fe)\n- [`7f14217c8b6` test: Extend util_ArgsMerge test to check for \"Multiple values specified\" errors](https://github.com/bitcoin/bitcoin/pull/17493/commits/7f14217c8b62bd646c82eec0bddd8db770b4947a)\n\n---\n\nEnable error \"Multiple values specified for -setting in same section of config file.\", for ALLOW_ANY settings that don't specify ALLOW_LIST.\n\nInstead of silently ignoring settings, this change makes it an error to provide an ambiguous config file that provides assigns multiple values to a single-value setting. Change includes release notes.\n\nPart of the motivation for this change is to improve usability and prevent settings that look valid from being silently ignored. Another motivation is to be able to remove confusing \"reverse precedence\" logic in #17581",
 "commits": [
  {
   "sha": "94300ae454e49d97415848fa144ff19893f53ac1",
   "date": "2026-07-13T20:29:09Z",
   "message": "common: Grammar / formatting tweaks\n\nImplement cleanup suggestions from l0rinc:\n\nhttps://github.com/bitcoin/bitcoin/pull/16545#discussion_r1773221823\nhttps://github.com/bitcoin/bitcoin/pull/16545#discussion_r1773291395\nhttps://github.com/bitcoin/bitcoin/pull/16545#discussion_r1775897382"
  },
  {
   "sha": "92cb734d5a4ed825669f796943229d80a71f7060",
   "date": "2026-07-13T20:29:09Z",
   "message": "doc: Add detailed ArgsManager type flag documention\n\nThis commit just adds documentation for the type flags. The flags are actually\nimplemented in the following two commits."
  },
  {
   "sha": "1500c5801cbb0db12634dd99905845711ffcb8a2",
   "date": "2026-07-13T20:29:09Z",
   "message": "common: Implement ArgsManager flags to parse and validate settings on startup\n\nThis commit implements support for new ALLOW_BOOL, ALLOW_INT, ALLOW_STRING, and\nALLOW_LIST flags by validating settings with these flags earlier on startup and\nproviding detailed error messages to users.\n\nThe new flags implement stricter error checking than ALLOW_ANY. For example, a\ndouble negated option like -nosetting=0 is treated like an error instead of\ntrue, and an unrecognized bool value like -setting=true is treated like an\nerror instead of false. And if a non-list setting is assigned multiple times in\nthe same section of a configuration file, the later assignments trigger errors\ninstead of being silently ignored.\n\nThe new flags also provide type information that allows ArgsManager\nGetSettings() and GetSettingsList() methods to return typed integer and boolean\nvalues instead of unparsed strings.\n\nThe changes in this commit have no effect on current application behavior\nbecause the new flags are only used in unit tests. The existing ALLOW_ANY\nchecks in the argsman_tests/CheckValueTest confirm that no behavior is changing\nfor current settings, which use ALLOW_ANY."
  },
  {
   "sha": "481099679b368be6c707ec536613f356b3543331",
   "date": "2026-07-13T20:29:09Z",
   "message": "common: Update ArgManager GetArg helper methods to work better with ALLOW flags\n\nUpdate GetArg, GetArgs, GetBoolArg, and GetIntArg helper methods to work\nconveniently with ALLOW_BOOL, ALLOW_INT, and ALLOW_STRING flags.\n\nThe GetArg methods are convenience wrappers around the GetSetting method. The\nGetSetting method returns the originally parsed settings values in their\ndeclared bool/int/string types, while the GetArg wrappers provide extra\ntype-coercion and default-value fallback features as additional conveniences\nfor callers.\n\nThis commit makes two changes to GetArg, GetArgs, GetBoolArg, and GetIntArg\nhelper methods when BOOL/INT/STRING flags are used:\n\n1. GetArg methods will now raise errors if they are called with inconsistent\n   flags. For example, GetArgs will raise a logic_error if it is called on a\n   non-LIST setting, GetIntArg will raise a logic_error if it is called\n   on a non-INT setting.\n\n2. GetArg methods will now avoid various type coersion footguns when they are\n   called on new BOOL/INT/STRING settings. Existing ALLOW_ANY settings are\n   unaffected. For example, negated settings will return \"\" empty strings\n   instead of \"0\" strings (in the past the \"0\" strings caused strangeness like\n   \"-nowallet\" options creating wallet files named \"0\"). The new behaviors are\n   fully specified and checked by the `CheckValueTest` unit test.\n\nThe ergonomics of the GetArg helper methods are subjective and the behaviors\nthey implement can be nitpicked and debated endlessly. But behavior of these\nhelper methods does not dictate application behavior, and they can be bypassed\nby calling GetSetting and GetSettingList methods instead. If it's necessary,\nbehavior of these helper methods can also be changed again in the future.\n\nThe changes have no effect on current application behavior because the new\nflags are only used in unit tests. The `setting_args` unit test and ALLOW_ANY\nchecks in the `CheckValueTest` unit test are unchanged and confirm that\n`GetArg` methods behave the same as before for ALLOW_ANY flags (returning the\nsame values and throwing the same exceptions)."
  },
  {
   "sha": "dadfea2ac55a036ab7aa93c6ad14d1f736c8872c",
   "date": "2026-07-13T20:29:09Z",
   "message": "test: Add tests to demonstrate usage of ArgsManager flags\n\nCo-authored-by: Hodlinator <172445034+hodlinator@users.noreply.github.com>"
  },
  {
   "sha": "abe4b1d8974f5171a5e15e2cc5cae2a2144bbb2c",
   "date": "2026-07-13T20:29:09Z",
   "message": "test: Add test for settings.json parsing with type flags\n\nThe type flags aren't currently used to validate or convert settings in the\nsettings.json file, but they should be in the future. Add test to check current\nbehavior that can be extended when flags are applied.\n\nCo-authored-by: Hodlinator <172445034+hodlinator@users.noreply.github.com>"
  },
  {
   "sha": "d134020611f17b6a26809fa31bac88d5a087ea61",
   "date": "2026-08-14T20:01:12Z",
   "message": "Merge branch 'pr/argcheck' into pr/wdlist"
  },
  {
   "sha": "671e54779624f80c7a0e5cb8e913bee2e3966c38",
   "date": "2026-08-14T20:01:12Z",
   "message": "common: Add support for combining ArgsManager flags\n\nLet ALLOW_STRING and ALLOW_INT flags be combined with ALLOW_BOOL so string and\nint options can be specified without explicit values. This is useful for\nimperative settings that trigger new behavior when specified and can accept\noptional string or integer values, but do not require them. (For examples, see\nthe example_options unit test modified in this commit.)"
  },
  {
   "sha": "44e71c8b9f9d688310f660dcb2a37bb55777825e",
   "date": "2026-08-14T20:01:12Z",
   "message": "scripted-diff: Add ALLOW_LIST flag to arguments retrieved with GetArgs\n\nThis change has no effect on behavior, and is basically just a documentation\nchange at this point. The ALLOW_LIST flag is currently ignored unless\nALLOW_BOOL, ALLOW_INT, or ALLOW_STRING flags are also present, and these flags\nare not used yet.\n\n-BEGIN VERIFY SCRIPT-\nfor f in `git grep -n 'GetArgs(' | grep -v _tests | sed -n 's/.*GetArgs(\"\\([^\"]\\+\\)\".*/\\1/p' | sort -u`; do\n   git grep -l -- \"$f\" | xargs sed -i \"/AddArg(\\\"$f[=\\\"]/ s/ArgsManager::ALLOW_ANY/& | ArgsManager::ALLOW_LIST/g\"\ndone\n-END VERIFY SCRIPT-"
  },
  {
   "sha": "bd820336f0b4da310e1921af3da24dac446537ae",
   "date": "2026-08-14T20:01:12Z",
   "message": "refactor: Fix more ALLOW_LIST arguments\n\n- Remove ALLOW_LIST flag from bitcoin-wallet -wallet and -debug arguments. They\n  are list arguments for bitcoind, but single arguments for bitcoin-wallet.\n\n- Add ALLOW_LIST flag to -includeconf arg (missed by scripted diff since it's\n  not accessed through GetArgs)\n\n- Add ALLOW_LIST flag to -proxy, -debug, -loglevel, -whitebind, and -whitelist\n  args (missed by scripted diff due to line breaks in AddArgs calls)\n\n- Add ALLOW_LIST flag to -zmq args (missed by scripted diff due to programmatic\n  GetArgs calls)\n\nThis change has no effect on behavior, and is basically just a documentation\nchange at this point. The ALLOW_LIST flag is currently ignored unless\nALLOW_BOOL, ALLOW_INT, or ALLOW_STRING flags are also present, and these flags\nare not used yet."
  },
  {
   "sha": "b314c7e7de54565649fa24b517f51bfa0f9b723e",
   "date": "2026-08-14T20:01:12Z",
   "message": "Always reject empty -blockfilterindex=\"\" arguments\n\nPrevious behavior was inconsistent: if -blockfilterindex or\n-blockfilterindex=\"\" arguments were specified they would normally enable all\nblock filter indexes, but could also trigger \"Unknown -blockfilterindex value\"\nerrors if followed by later -blockfilterindex arguments.\n\nIt was confusing that the same -blockfilterindex options could sometime trigger\nerrors and sometimes not depending on option position. It was also confusing\nthat an empty -blockfilterindex=\"\" setting could enable all indexes even though\nindexes are disabled by default.\n\nNew behavior is more straightforward:\n\n- -blockfilterindex and -blockfilterindex=1 always enable indexes\n- -noblockfilterindex and -blockfilterindex=0 always disable indexes\n- -blockfilterindex=\"\" is always an unknown value error\n\nThe meaning of these options no longer changes based on option position."
  },
  {
   "sha": "bf58582fd49f0edc9aef6f49117a4d40ea14ea19",
   "date": "2026-08-14T20:01:12Z",
   "message": "refactor: Stop calling GetArg/IsArgSet on ALLOW_LIST options\n\nUpcoming commits will make it an error to call GetArg and IsArgSet methods on\nlist options since these usages are error prone. For example GetArg will return\nlast command line value but first config value in the list, and IsArgSet will\nreturn true even if the list is empty if the list was negated.\n\nThis change is just a refactoring replacing problematic ArgsManager calls with\nequivalent calls to avoid changing any behavior. Current behavior could\nprobably be improved in these cases, but this change should make new problems\nless likely to be introduced."
  },
  {
   "sha": "581eaaf10fc8ce584332fdcc5f04c245f3df7ed2",
   "date": "2026-08-14T20:01:12Z",
   "message": "refactor: Always enforce ALLOW_LIST in CheckArgFlags\n\nPrevent GetArg() from being called on ALLOW_LIST arguments, and GetArgs() from\nbeing called on non-list arguments.\n\nThis checking was previously skipped unless typed INT/BOOL/STRING flags were\npresent, but now it's always done.\n\nThis change has no effect on external behavior. It is just supposed to enforce\ninternal consistency and prevent bugs caused by using the wrong GetArg method\nto retrieve settings."
  },
  {
   "sha": "bf61922ae3951787d2a708d4318951c52d4b93dd",
   "date": "2026-08-14T20:01:12Z",
   "message": "Merge branch 'pr/wdlist' into pr/wdmult"
  },
  {
   "sha": "b46958a1ac3ab702ac7a654d0e915e4b7ff0022b",
   "date": "2026-08-14T20:01:12Z",
   "message": "util: Forbid ambiguous multiple assignments in config file\n\nEnable error \"Multiple values specified for -setting in same section of config\nfile.\", for ALLOW_ANY settings that don't specify ALLOW_LIST.\n\nInstead of silently ignoring settings, this change makes it an error to provide\nan ambiguous config file that provides assigns multiple values to a\nsingle-value setting. Change include release notes."
  },
  {
   "sha": "bdde19f29edb4c18459b0512ef75c819ec5fe877",
   "date": "2026-08-14T20:01:12Z",
   "message": "test: Extend util_ArgsMerge test to check for \"Multiple values specified\" errors\n\nAlso skip calling TestArgString in these cases since exact behavior retrieving\nvalues is irrelevant when parsing values fails.\n\nAlso s/TestArgString/GetArg/ to be more efficient and direct, now that it's no\nlonger necessary to call with separation of ALLOW_LIST and non ALLOW_LIST\ncases."
  },
  {
   "sha": "31de2cc896f63f11d2abdbf7640f4b657bf87b78",
   "date": "2026-08-14T20:01:12Z",
   "message": "test-each-commit: Increase fetch depth\n\nNeeded due to base PR, can be dropped before merge"
  }
 ],
 "timeline": [
  {
   "t": null,
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "PENDING",
   "commit": "39207eed6cf2a3e8b8e09e52387e31421a66e340",
   "text": ""
  },
  {
   "t": "2019-11-18T21:18:45Z",
   "kind": "review_comment",
   "who": "JeremyRubin",
   "assoc": "CONTRIBUTOR",
   "path": "src/util/system.cpp",
   "commit": "9b79d0e8daa6e7dd5b5b69d2933e052d07f61d17",
   "in_reply_to": null,
   "text": "Perhaps only err if the value differs?"
  },
  {
   "t": "2019-11-18T21:23:22Z",
   "kind": "review",
   "who": "JeremyRubin",
   "assoc": "CONTRIBUTOR",
   "state": "COMMENTED",
   "commit": "e81c6ea28d72bba266eb8416550ea1776e72c726",
   "text": "Concept ACK.\n\nCurious if you think this has a high likelihood of breaking a lot of configs in the wild -- but I suppose it's worth it, as anything which could be intentionally repeated gets the new flag.\n\nOne interesting point: if something is *not* allow list, but receives a new param that is identical to the last set one, we could allow it? Something like this could be useful for certain bool settings if config files are being merged.\n\nNoting for reference tracking that #12763 will require an update after this is merged."
  },
  {
   "t": "2019-11-21T22:50:33Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "c011a7f09af7916a85fb6a6c54ebcb2302f9268b"
  },
  {
   "t": "2019-11-24T20:10:10Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "4a79e385b6ee8712ab3f43f43e519b86bc19f505"
  },
  {
   "t": "2019-11-27T23:17:36Z",
   "kind": "review",
   "who": "Khailand69",
   "assoc": "NONE",
   "state": "APPROVED",
   "commit": "4a79e385b6ee8712ab3f43f43e519b86bc19f505",
   "text": ""
  },
  {
   "t": "2019-12-20T16:03:38Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "39207eed6cf2a3e8b8e09e52387e31421a66e340"
  },
  {
   "t": "2020-01-09T05:16:43Z",
   "kind": "comment",
   "who": "ajtowns",
   "assoc": "MEMBER",
   "text": "Weak concept NACK on this, precedence in config files might be confusing but it's not ambiguous and specifying `setting=1 \\n setting=2` is something you might plausibly see in the wild, so this change has the potential to cause systems to not restart correctly... Maybe having a warning rather than an error for a release would be better? Still, better to make the change once for everything than gradually as things get switched away from ALLOW_ANY to something more specific."
  },
  {
   "t": "2020-01-09T20:18:00Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nThis description sounds a little misleading to me. It is true that if someone had an ambiguous config file, and they updated to a new bitcoin version and then restarted without testing, they would see a \"Multiple values specified for -foo in same section of config file\" init error. But there wouldn't be a question of correctness, or risk that the new version would start up using different settings than the old version.\n\nPersonally, I don't think a debug log warning would be as good as an error here, given experience with issues like #15629 where warnings have seemed pretty easy to miss. I understand your concern about the case where someone upgrades their version of bitcoin and sees an error about an insignificant ambiguity in their config file. But I wouldn't want to forget about cases where someone could upgrade bitcoin be prompted to fix config errors that actually affected their privacy or security.\n\nI wonder what you think about Jeremy's suggestion to prevent errors in more spurious cases where a setting is repeated but the value doesn't change: https://github.com/bitcoin/bitcoin/pull/17493#pullrequestreview-318636254. It'd be pretty easy to tweak the PR to avoid triggering errors in these cases.--\n\n---\n\nRebased 98e2bba7054c82eeddf1f5565362ec901207aeda -> 68d1b626ac2fc7d5293bd9e70985fbf899decff8 ([`pr/wdmult.17`](https://github.com/ryanofsky/bitcoin/commits/pr/wdmult.17) -> [`pr/wdmult.18`](https://github.com/ryanofsky/bitcoin/commits/pr/wdmult.18), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/wdmult.17-rebase..pr/wdmult.18))\n\nRebased 68d1b626ac2fc7d5293bd9e70985fbf899decff8 -> 20119c310f4e280488c310427e1fa58f7056e81a ([`pr/wdmult.18`](https://github.com/ryanofsky/bitcoin/commits/pr/wdmult.18) -> [`pr/wdmult.19`](https://github.com/ryanofsky/bitcoin/commits/pr/wdmult.19), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/wdmult.18-rebase..pr/wdmult.19))\n\nRebased 20119c310f4e280488c310427e1fa58f7056e81a -> 24078e372fa35717e3330721914136ab14a19834 ([`pr/wdmult.19`](https://github.com/ryanofsky/bitcoin/commits/pr/wdmult.19) -> [`pr/wdmult.20`](https://github.com/ryanofsky/bitcoin/commits/pr/wdmult.20), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/wdmult.19-rebase..pr/wdmult.20)) on top of #17580 pr/wdlist.31\n\nRebased 24078e372fa35717e3330721914136ab14a19834 -> ab0963226f8c4816d8e84ee01073de19a5913ffb ([`pr/wdmult.20`](https://github.com/ryanofsky/bitcoin/commits/pr/wdmult.20) -> [`pr/wdmult.21`](https://github.com/ryanofsky/bitcoin/commits/pr/wdmult.21), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/wdmult.20-rebase..pr/wdmult.21)) on top of #17580 pr/wdlist.33\n\nRebased ab0963226f8c4816d8e84ee01073de19a5913ffb -> 2709b51f31933cea9051413d14e0eb2eed2e2a78 ([`pr/wdmult.21`](https://github.com/ryanofsky/bitcoin/commits/pr/wdmult.21) -> [`pr/wdmult.22`](https://github.com/ryanofsky/bitcoin/commits/pr/wdmult.22), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/wdmult.21-rebase..pr/wdmult.22)) on top of #17580 pr/wdlist.34 with no changes\n\nRebased 2709b51f31933cea9051413d14e0eb2eed2e2a78 -> 7f14217c8b62bd646c82eec0bddd8db770b4947a ([`pr/wdmult.22`](https://github.com/ryanofsky/bitcoin/commits/pr/wdmult.22) -> [`pr/wdmult.23`](https://github.com/ryanofsky/bitcoin/commits/pr/wdmult.23), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/wdmult.22-rebase..pr/wdmult.23)) due to conflict with #35441"
  },
  {
   "t": "2020-01-23T05:52:31Z",
   "kind": "comment",
   "who": "ajtowns",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nSure; I meant \"restart correctly\" as in \"keep working the way things are supposed to rather than gratuitously break and cause the sysadmin headaches\" :) But yeah, I agree a warning everyone will miss isn't that helpful, and there aren't any better approaches coming to mind; really that's what release notes and being careful about upgrades are for.\n\nI'd probably wait to see someone using it in real life before adding special cases for duplicate settings with the same param/value."
  },
  {
   "t": "2020-09-28T12:57:03Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "77623d1dc643f9a69476cb1297d223bad786a972"
  },
  {
   "t": "2021-04-13T03:10:29Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "53c19cd8310ef2187bf3ef430a53d83a6e5c0414"
  },
  {
   "t": "2021-06-16T20:26:37Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "7a66e8a1e3b420022f7116529f7b078b3604eaa9"
  },
  {
   "t": "2021-12-30T21:19:24Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "ca8d268011b53315652535bab86db95d2ec4c4f2"
  },
  {
   "t": "2022-09-27T18:23:17Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "bcd3e36d6e977e59ea542ff74242c0a538f741a0"
  },
  {
   "t": "2022-11-29T23:28:51Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "0401590f645af27bbce6409a1d06aa127378ce33"
  },
  {
   "t": "2023-02-08T11:25:36Z",
   "kind": "comment",
   "who": "fanquake",
   "assoc": "MEMBER",
   "text": "Moved this to draft for now, given it's based on multiple other PRs, some of which are also drafts."
  },
  {
   "t": "2023-02-15T02:54:56Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "20ace2d096420974689fe18b8fa73d120d7c6d10"
  },
  {
   "t": "2023-05-03T21:20:35Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "c65e3b3b7d1e9dc33ecf5f0029430ef90f765cf8"
  },
  {
   "t": "2024-07-19T23:07:26Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "67bbec94c33f1e117fdd26d130ec68724e64ea17"
  },
  {
   "t": "2024-08-06T16:41:01Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "6a42b8e1d4ef89dda7237d2fee3fe70092928441"
  },
  {
   "t": "2024-12-06T18:59:34Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "ec1698a0a37015bbc9323d1d72428f57d780050b"
  },
  {
   "t": "2025-03-12T18:22:46Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "e064f20d8a8a3746040ccde52ef3b4b492aa858a"
  },
  {
   "t": "2025-08-04T17:51:10Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "98e2bba7054c82eeddf1f5565362ec901207aeda"
  },
  {
   "t": "2025-12-12T12:18:57Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "68d1b626ac2fc7d5293bd9e70985fbf899decff8"
  },
  {
   "t": "2025-12-16T02:10:17Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "20119c310f4e280488c310427e1fa58f7056e81a"
  },
  {
   "t": "2026-01-18T23:06:34Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "24078e372fa35717e3330721914136ab14a19834"
  },
  {
   "t": "2026-04-01T21:50:24Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "ab0963226f8c4816d8e84ee01073de19a5913ffb"
  },
  {
   "t": "2026-06-08T16:41:11Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "b6794bddf85340b0e1d52d73f831fd45c8f0ef19"
  },
  {
   "t": "2026-06-24T15:28:15Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "0e4d6342ffa6d4f9b5046c63b1bd2576b60ee00a"
  },
  {
   "t": "2026-08-15T16:11:18Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "31de2cc896f63f11d2abdbf7640f4b657bf87b78"
  }
 ],
 "labels_log": [
  {
   "t": "2019-11-15T22:12:21Z",
   "action": "labeled",
   "label": "Utils/log/libs",
   "who": "fanquake"
  },
  {
   "t": "2019-11-15T22:12:29Z",
   "action": "labeled",
   "label": "Refactoring",
   "who": "fanquake"
  },
  {
   "t": "2019-12-19T20:15:42Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2019-12-20T16:53:51Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2020-01-30T22:50:48Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2020-09-28T13:11:42Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2020-09-29T07:59:56Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2021-04-13T03:56:22Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2021-04-15T04:01:32Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2021-06-16T20:55:40Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2021-08-22T01:58:54Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2021-12-30T21:32:55Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2022-02-09T23:11:31Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2022-09-27T18:31:55Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2022-11-15T21:17:25Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2022-11-30T01:22:49Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2023-01-11T13:56:03Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2023-02-15T04:23:46Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2023-03-20T18:46:41Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2023-05-03T23:17:19Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2023-05-09T16:37:49Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2024-07-20T00:28:37Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2024-08-05T01:42:10Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2024-08-06T18:00:24Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2024-08-07T22:12:37Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2024-12-06T19:21:54Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2024-12-14T01:18:14Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2025-03-12T18:28:06Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2025-03-14T01:36:17Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2025-06-11T06:59:31Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "maflcko"
  },
  {
   "t": "2025-06-11T06:59:37Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "maflcko"
  },
  {
   "t": "2025-08-04T18:12:36Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2025-11-21T23:34:43Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2025-12-12T13:18:50Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2025-12-12T18:46:56Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-01-19T00:23:25Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-01-27T13:51:50Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-01T22:52:15Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-03T22:30:33Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-08T17:26:02Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-15T21:43:08Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-24T16:05:52Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-04T20:51:02Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-15T17:51:11Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  }
 ],
 "state_log": [
  {
   "t": "2019-11-24T20:21:20Z",
   "kind": "renamed",
   "who": "ryanofsky",
   "from": "util: Forbid ambiguous repeated assignments in config file",
   "to": "util: Forbid ambiguous multiple assignments in config file"
  },
  {
   "t": "2023-02-08T11:25:07Z",
   "kind": "convert_to_draft",
   "who": "fanquake"
  }
 ],
 "text_chars": 15112,
 "text_tokens_estimate": 3778,
 "changed_paths": [
  ".github/workflows/ci.yml",
  "doc/release-notes-17493.md",
  "src/chainparamsbase.cpp",
  "src/common/args.cpp",
  "src/common/args.h",
  "src/common/config.cpp",
  "src/init.cpp",
  "src/init/common.cpp",
  "src/test/argsman_tests.cpp",
  "src/test/fuzz/system.cpp",
  "src/test/getarg_tests.cpp",
  "src/test/logging_tests.cpp",
  "src/test/util/common.h",
  "src/wallet/init.cpp",
  "test/functional/feature_config_args.py",
  "test/lint/check-doc.py"
 ],
 "files": [
  {
   "path": ".github/workflows/ci.yml",
   "add": 1,
   "del": 1
  },
  {
   "path": "doc/release-notes-17493.md",
   "add": 8,
   "del": 0
  },
  {
   "path": "src/chainparamsbase.cpp",
   "add": 4,
   "del": 4
  },
  {
   "path": "src/common/args.cpp",
   "add": 158,
   "del": 49
  },
  {
   "path": "src/common/args.h",
   "add": 162,
   "del": 21
  },
  {
   "path": "src/common/config.cpp",
   "add": 7,
   "del": 1
  },
  {
   "path": "src/init.cpp",
   "add": 44,
   "del": 36
  },
  {
   "path": "src/init/common.cpp",
   "add": 3,
   "del": 3
  },
  {
   "path": "src/test/argsman_tests.cpp",
   "add": 689,
   "del": 71
  },
  {
   "path": "src/test/fuzz/system.cpp",
   "add": 47,
   "del": 7
  },
  {
   "path": "src/test/getarg_tests.cpp",
   "add": 61,
   "del": 3
  },
  {
   "path": "src/test/logging_tests.cpp",
   "add": 3,
   "del": 3
  },
  {
   "path": "src/test/util/common.h",
   "add": 4,
   "del": 0
  },
  {
   "path": "src/wallet/init.cpp",
   "add": 1,
   "del": 1
  },
  {
   "path": "test/functional/feature_config_args.py",
   "add": 1,
   "del": 1
  },
  {
   "path": "test/lint/check-doc.py",
   "add": 3,
   "del": 2
  }
 ],
 "test_lines": 895,
 "git": {
  "head": "31de2cc896f63f11d2abdbf7640f4b657bf87b78",
  "head_matches_backup": true,
  "base": "683e05a265c86fee6075ccd81828b19e0d8e131a",
  "commits": [
   {
    "sha": "94300ae454",
    "subject": "common: Grammar / formatting tweaks",
    "files": 2,
    "add": 4,
    "del": 4
   },
   {
    "sha": "92cb734d5a",
    "subject": "doc: Add detailed ArgsManager type flag documention",
    "files": 2,
    "add": 137,
    "del": 18
   },
   {
    "sha": "1500c5801c",
    "subject": "common: Implement ArgsManager flags to parse and validate settings on startup",
    "files": 5,
    "add": 194,
    "del": 16
   },
   {
    "sha": "481099679b",
    "subject": "common: Update ArgManager GetArg helper methods to work better with ALLOW flags",
    "files": 4,
    "add": 174,
    "del": 80
   },
   {
    "sha": "dadfea2ac5",
    "subject": "test: Add tests to demonstrate usage of ArgsManager flags",
    "files": 2,
    "add": 312,
    "del": 0
   },
   {
    "sha": "abe4b1d897",
    "subject": "test: Add test for settings.json parsing with type flags",
    "files": 1,
    "add": 61,
    "del": 3
   },
   {
    "sha": "d134020611",
    "subject": "Merge branch 'pr/argcheck' into pr/wdlist",
    "files": 9,
    "add": 851,
    "del": 90
   },
   {
    "sha": "671e547796",
    "subject": "common: Add support for combining ArgsManager flags",
    "files": 4,
    "add": 138,
    "del": 20
   },
   {
    "sha": "44e71c8b9f",
    "subject": "scripted-diff: Add ALLOW_LIST flag to arguments retrieved with GetArgs",
    "files": 6,
    "add": 27,
    "del": 27
   },
   {
    "sha": "bd820336f0",
    "subject": "refactor: Fix more ALLOW_LIST arguments",
    "files": 3,
    "add": 13,
    "del": 13
   },
   {
    "sha": "b314c7e7de",
    "subject": "Always reject empty -blockfilterindex=\"\" arguments",
    "files": 1,
    "add": 8,
    "del": 7
   },
   {
    "sha": "bf58582fd4",
    "subject": "refactor: Stop calling GetArg/IsArgSet on ALLOW_LIST options",
    "files": 1,
    "add": 11,
    "del": 4
   },
   {
    "sha": "581eaaf10f",
    "subject": "refactor: Always enforce ALLOW_LIST in CheckArgFlags",
    "files": 3,
    "add": 121,
    "del": 61
   },
   {
    "sha": "bf61922ae3",
    "subject": "Merge branch 'pr/wdlist' into pr/wdmult",
    "files": 14,
    "add": 1143,
    "del": 196
   },
   {
    "sha": "b46958a1ac",
    "subject": "util: Forbid ambiguous multiple assignments in config file",
    "files": 3,
    "add": 15,
    "del": 5
   },
   {
    "sha": "bdde19f29e",
    "subject": "test: Extend util_ArgsMerge test to check for \"Multiple values specified\" errors",
    "files": 1,
    "add": 42,
    "del": 6
   },
   {
    "sha": "31de2cc896",
    "subject": "test-each-commit: Increase fetch depth",
    "files": 1,
    "add": 1,
    "del": 1
   }
  ],
  "patch_truncated": true
 },
 "input_hash": "c58c9f265a947f82",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}