Skip to content

Bug: quickfiler-navigation-key-collision #232

Closed

Description

@drmoisan
  • Work Mode: full-bug

Summary

QuickFiler throws System.ArgumentException: Cannot add key because it already exists. Key 2 SourceId Collection when a page transition (OK/Skip, including the automatic skip triggered by popping out the last item on a page) swaps in a new page without unregistering the outgoing page's keyboard navigation keys or registering the incoming page's keys, leaving stale "Collection"-sourced keys in the shared KbdActions registry that later collide. Bundled with this fix, at the user's request, is an additive debug-logging change so that every folder-confidence probability calculation is logged (item summary, score, caller) to make a separately-observed "only a subset of items appears in high-confidence mode" symptom empirically diagnosable in future sessions.

Environment

  • OS/version: Windows (VSTO Outlook add-in host)
  • Repo/branch: TaskMaster, branch TaskMaster-wt-2026-07-03-10-11, HEAD 00507b59
  • Command/flags used: QuickFiler run in "high confidence mode"
  • Data source or fixture: Live Outlook inbox (production run, not a test fixture)

Steps to Reproduce

  1. Run QuickFiler in high-confidence mode with a page that has exactly one item.
  2. Click the "pop out" button for that item.
  3. Internally: RemoveSpecificControlGroupAsync unregisters the current page's key(s), removes the item (count reaches 0), and calls QfcFormController.SkipGroupAsync() to bring forward the next cached page via LoadControlsAndHandlers_01(TableLayoutPanel, List<QfcItemGroup>), which swaps _itemGroups without calling UnregisterNavigation()/RegisterNavigation().
  4. RemoveSpecificControlGroupAsync then unconditionally calls RegisterNavigation() again for the newly swapped-in page.
  5. If any key in the newly-active page's range ("1".."N") is still occupied by an orphaned entry left behind by an earlier page that was abandoned mid-page via the same defective swap path (OK or Skip while items remained), KbdActions.Add throws ArgumentException.

Expected Behavior

Keyboard digit-navigation keys ("1".."N", SourceId = "Collection") always match exactly the currently-displayed page's items, regardless of whether the page changed via individual item removal, "OK" (move + load next), or "Skip". No stale keys should ever remain registered for a page that is no longer displayed.

Actual Behavior

QfcCollectionController.LoadControlsAndHandlers_01(TableLayoutPanel, List<QfcItemGroup>) (QuickFiler/Controllers/QfcCollectionController.cs:252-262) - the swap-in path used by both the "OK" flow (QfcFormController.EventHandlers.cs:136-143) and the "Skip" flow (QfcFormController.EventHandlers.cs:361-395, also invoked internally from RemoveSpecificControlGroupAsync's zero-item branch) - never calls UnregisterNavigation() for the outgoing page or RegisterNavigation()/WireUpAsyncKeyboardHandler() for the incoming page. Its unused sibling SwapItemGroups (line 870-878) shows the correct pattern. _kbdHandler.StringActionsAsync is a single, session-lifetime collection shared across all pages, so keys orphaned by this gap collide the next time RegisterNavigation() walks from position 0 - which happens unconditionally at the end of RemoveSpecificControlGroupAsync (line 1219).

Logs / Screenshots

  • Attached minimal logs or screenshot
  • Snippet:
System.ArgumentException
  HResult=0x80070057
  Message=Cannot add key because it already exists. Key 2 SourceId Collection
Parameter name: instance
  Source=QuickFiler
  StackTrace:
   at QuickFiler.Controllers.KbdActions`3.Add(UClass instance) in KbdActions.cs:line 121
   at QuickFiler.Controllers.QfcCollectionController.RegisterNavigationAsyncAction(Int32 itemIndex, Int32 digits) in QfcCollectionController.cs:line 1346
   at QuickFiler.Controllers.QfcCollectionController.RegisterNavigation() in QfcCollectionController.cs:line 1325
   at QuickFiler.Controllers.QfcCollectionController.<RemoveSpecificControlGroupAsync>d__96.MoveNext() in QfcCollectionController.cs:line 1219
   at QuickFiler.Controllers.QfcCollectionController.<PopOutControlGroupAsync>d__84.MoveNext() in QfcCollectionController.cs:line 966
   at QuickFiler.Controllers.QfcItemController.<BtnPopOut_Click>d__163.MoveNext() in QfcItemController.EventHandlers.cs:line 67

Impact / Severity

  • High
  • Blocker
  • Medium
  • Low

Rationale: crashes the active QuickFiler session (unhandled exception surfaced to the user) during ordinary bulk-processing use; reachable via everyday OK/Skip page transitions, not an edge case.

Source

From: docs/features/potential/2026-07-03-quickfiler-navigation-key-collision.md

Activity

  1. added a commit that references this issue on Jul 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions