{"record":{"id":"6bb3b3e1d18a883c","repo":"fluent/fluentd","slug":"invalid-params","errorCode":"invalid_params","errorMessage":"#{key} already exists in counter","messagePattern":"#(.+?) already exists in counter","errorType":"exception","errorClass":"Fluent::Counter::InvalidParams","httpStatus":null,"severity":"warning","filePath":"lib/fluent/counter/store.rb","lineNumber":76,"sourceCode":"        end\n\n        # storage_local calls PluginId#plugin_root_dir\n        def plugin_root_dir\n          nil\n        end\n      end\n\n      def start\n        @storage.load\n      end\n\n      def stop\n        @storage.save\n      end\n\n      def init(key, data, ignore: false)\n        ret = if v = get(key)\n                raise InvalidParams.new(\"#{key} already exists in counter\") unless ignore\n                v\n              else\n                @storage.put(key, build_value(data))\n              end\n\n        build_response(ret)\n      end\n\n      def get(key, raise_error: false, raw: false)\n        ret = if raise_error\n                @storage.get(key) or raise UnknownKey.new(\"`#{key}` doesn't exist in counter\")\n              else\n                @storage.get(key)\n              end\n        if raw\n          ret\n        else\n          ret && build_response(ret)","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/fluent/fluentd/blob/dd45c6e18dc7be33b5e5a0f0767bf46307ff5626/lib/fluent/counter/store.rb#L58-L94","documentation":"Fluentd's Windows supervisor runs a dedicated signal thread (install_windows_event_handler, lib/fluent/supervisor.rb:290) that waits on named Win32 events (STOP/HUP/USR1/USR2/CONT, plus 5 more when --signame is set) via Win32::Ipc#wait_any, which wraps the Win32 WaitForMultipleObjects API. The expected contract is a 1-based index of the signaled event; this warning fires when wait_any returns anything outside 1..events.length, i.e. 0 (WAIT_TIMEOUT, unexpected with the infinite 0xFFFFFFFF timeout) or a WAIT_FAILED-style error value. It means the wait call itself misbehaved (invalid/closed handle, gem version with different return semantics, duplicate event names), so no reliable signal can be dispatched.","triggerScenarios":"Calling Win32::Ipc#wait_any with the 6 (or 11 with @signame) named events built in install_windows_event_handler and receiving 0, a negative value, or a value > events.length. Concretely: (a) the win32-event/win32-ipc gem version returns 0-based or nil results instead of 1-based; (b) a handle was closed while the wait was pending (e.g. stop_windows_event_thread closed the events in the ensure block during shutdown, leaving stale handles); (c) two fluentd instances share the same --signame so the named events collide and the wait fails; (d) WaitForMultipleObjects returns WAIT_FAILED for an invalid handle.","commonSituations":"Running fluentd/td-agent as a Windows service after a gem upgrade that changed win32-event semantics; multiple fluentd processes configured with the same signame; shutdown/restart races where the event objects are closed while the signal thread is still inside wait_any; environments where the bundled gem set diverges from fluentd's Gemfile.lock.","solutions":["Check gem compatibility: run fluent-gem list win32-event win32-ipc and align them with the versions pinned in fluentd's Gemfile.lock for your release; reinstall with fluent-gem install -v <pinned version> if they diverge.","Ensure the --signame (if set) is unique per fluentd instance on the machine and no leftover fluentd processes hold the same named events (tasklist | findstr fluentd, then stop duplicates).","Upgrade fluentd to the latest 1.x patch release, which contains fixes to the Windows event handling thread.","Reproduce with the ipc_idx value from the log: 0 means timeout/WAIT_FAILED surfaced as 0, a large value points to a handle-count/validity problem - use it to decide between gem downgrade and handle-investigation.","Restart the service after a clean shutdown (all fluentd child processes exited) so the named events are recreated fresh."],"exampleFix":"// before (lib/fluent/supervisor.rb:317-327)\nipc_idx = ipc.wait_any(events.map {|e| e[:win32_event]}, infinite)\nevent_idx = ipc_idx - 1\nif event_idx >= 0 && event_idx < events.length\n  $log.debug(\"Got Win32 event \\\"#{events[event_idx][:win32_event].name}\\\"\")\nelse\n  $log.warn(\"Unexpected return value of Win32::Ipc#wait_any: #{ipc_idx}\")\nend\ncase events[event_idx][:action] # events[-1] silently dispatches the LAST event!\n\n// after\nipc_idx = ipc.wait_any(events.map {|e| e[:win32_event]}, infinite)\nevent_idx = ipc_idx - 1\nunless event_idx >= 0 && event_idx < events.length\n  $log.warn(\"Unexpected return value of Win32::Ipc#wait_any: #{ipc_idx}\")\n  next # never dispatch on events[-1]; re-enter the wait loop\nend\ncase events[event_idx][:action]","handlingStrategy":"validation","validationCode":"# before entering the wait loop (fork of install_windows_event_handler)\nMAX_WAIT_OBJECTS = 64 # WaitForMultipleObjects hard limit\nunless events.all? { |e| e[:win32_event].is_a?(Win32::Event) }\n  raise ArgumentError, 'every wait object must be a Win32::Event'\nend\nif events.size > MAX_WAIT_OBJECTS\n  raise ArgumentError, \"too many events for WaitForMultipleObjects: #{events.size}\"\nend","typeGuard":"# Ruby guard for the wait_any contract (1-based index in range)\ndef valid_wait_index?(ipc_idx, events)\n  ipc_idx.is_a?(Integer) && (1..events.length).cover?(ipc_idx)\nend\n\nipc_idx = ipc.wait_any(handles, 0xFFFFFFFF)\nevent_idx = ipc_idx - 1\nnext unless valid_wait_index?(ipc_idx, events) # events[-1] must never dispatch","tryCatchPattern":"begin\n  ipc_idx = ipc.wait_any(events.map { |e| e[:win32_event] }, 0xFFFFFFFF)\nrescue => e\n  $log.error(\"Win32::Ipc#wait_any raised: #{e.class}: #{e.message}\")\n  next # re-enter loop; do not index events with a bogus value\nend","preventionTips":["Pin win32-event / win32-ipc to the versions in fluentd's Gemfile.lock and verify after any gem update (fluent-gem list win32-event).","Give every fluentd instance on a host a unique --signame so named events never collide.","Never dispatch on events[event_idx] without a range check - Ruby's negative indexing silently selects the last event.","Restart the service only after all fluentd child processes exit, so named Win32 events are recreated without stale handles."],"tags":["windows","win32-event","signals","supervisor","waitformultipleobjects","fluentd"],"backgroundTag":"waitformultipleobjects-failed","analyzedSha":"dd45c6e18dc7be33b5e5a0f0767bf46307ff5626","analyzedAt":"2026-08-21T16:22:07.332Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}